src/plugins/imageformats/svg/qsvgiohandler.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    46 #include "qsvgrenderer.h"
    46 #include "qsvgrenderer.h"
    47 #include "qimage.h"
    47 #include "qimage.h"
    48 #include "qpixmap.h"
    48 #include "qpixmap.h"
    49 #include "qpainter.h"
    49 #include "qpainter.h"
    50 #include "qvariant.h"
    50 #include "qvariant.h"
       
    51 #include "qbuffer.h"
    51 #include "qdebug.h"
    52 #include "qdebug.h"
    52 
    53 
    53 QT_BEGIN_NAMESPACE
    54 QT_BEGIN_NAMESPACE
    54 
    55 
    55 class QSvgIOHandlerPrivate
    56 class QSvgIOHandlerPrivate
    56 {
    57 {
    57 public:
    58 public:
    58     QSvgIOHandlerPrivate()
    59     QSvgIOHandlerPrivate(QSvgIOHandler *qq)
    59         : r(new QSvgRenderer()), loaded(false)
    60         : q(qq), loaded(false), readDone(false), backColor(Qt::transparent)
    60     {}
    61     {}
    61     ~QSvgIOHandlerPrivate()
       
    62     {
       
    63         delete r;
       
    64     }
       
    65 
    62 
    66     bool load(QIODevice *device);
    63     bool load(QIODevice *device);
    67     static bool findSvgTag(QIODevice *device);
    64 
    68 
    65     QSvgIOHandler   *q;
    69     QSvgRenderer *r;
    66     QSvgRenderer     r;
    70     QSize         defaultSize;
    67     QXmlStreamReader xmlReader;
    71     QSize         currentSize;
    68     QSize            defaultSize;
    72     bool          loaded;
    69     QRect            clipRect;
       
    70     QSize            scaledSize;
       
    71     QRect            scaledClipRect;
       
    72     bool             loaded;
       
    73     bool             readDone;
       
    74     QColor           backColor;
    73 };
    75 };
    74 
    76 
       
    77 
    75 bool QSvgIOHandlerPrivate::load(QIODevice *device)
    78 bool QSvgIOHandlerPrivate::load(QIODevice *device)
    76 {
    79 {
    77     if (loaded)
    80     if (loaded)
    78         return true;
    81         return true;
    79 
    82     if (q->format().isEmpty())
    80     if (r->load(device->readAll())) {
    83         q->canRead();
    81         defaultSize = QSize(r->viewBox().width(), r->viewBox().height());
    84 
    82         if (currentSize.isEmpty())
    85     // # The SVG renderer doesn't handle trailing, unrelated data, so we must
    83             currentSize = defaultSize;
    86     // assume that all available data in the device is to be read.
    84     }
    87     bool res = false;
    85     loaded = r->isValid();
    88     QBuffer *buf = qobject_cast<QBuffer *>(device);
       
    89     if (buf) {
       
    90         const QByteArray &ba = buf->data();
       
    91         res = r.load(QByteArray::fromRawData(ba.constData() + buf->pos(), ba.size() - buf->pos()));
       
    92         buf->seek(ba.size());
       
    93     } else if (q->format() == "svgz") {
       
    94         res = r.load(device->readAll());
       
    95     } else {
       
    96         xmlReader.setDevice(device);
       
    97         res = r.load(&xmlReader);
       
    98     }
       
    99 
       
   100     if (res) {
       
   101         defaultSize = QSize(r.viewBox().width(), r.viewBox().height());
       
   102         loaded = true;
       
   103     }
    86 
   104 
    87     return loaded;
   105     return loaded;
    88 }
   106 }
    89 
   107 
    90 bool QSvgIOHandlerPrivate::findSvgTag(QIODevice *device)
   108 
    91 {
   109 QSvgIOHandler::QSvgIOHandler()
    92     qint64 pos = device->pos();
   110     : d(new QSvgIOHandlerPrivate(this))
    93     device->seek(0);
   111 {
    94     char buffer[256];
   112 
    95     const char svg_tag[] = "<svg";
   113 }
    96 
   114 
    97     while (1) {
   115 
    98         int size = device->read(buffer, 256);
   116 QSvgIOHandler::~QSvgIOHandler()
    99         for (int i=0; i<size - 5; ++i) {
   117 {
   100             if (!memcmp(buffer + i, svg_tag, 4)) {
   118     delete d;
   101                 if (buffer[i+4] == ' ' || buffer[i+4] == '\t'
   119 }
   102                     || buffer[i+4] == '\n' || buffer[i+4] == '\r')
   120 
   103                 {
   121 
   104                     device->seek(pos);
   122 bool QSvgIOHandler::canRead() const
   105                     return true;
   123 {
   106                 }
   124     if (!device())
       
   125         return false;
       
   126     if (d->loaded && !d->readDone)
       
   127         return true;        // Will happen if we have been asked for the size
       
   128 
       
   129     QByteArray buf = device()->peek(8);
       
   130     if (buf.startsWith("\x1f\x8b")) {
       
   131         setFormat("svgz");
       
   132         return true;
       
   133     } else if (buf.contains("<?xml") || buf.contains("<svg")) {
       
   134         setFormat("svg");
       
   135         return true;
       
   136     }
       
   137     return false;
       
   138 }
       
   139 
       
   140 
       
   141 QByteArray QSvgIOHandler::name() const
       
   142 {
       
   143     return "svg";
       
   144 }
       
   145 
       
   146 
       
   147 bool QSvgIOHandler::read(QImage *image)
       
   148 {
       
   149     if (!d->readDone && d->load(device())) {
       
   150         bool xform = (d->clipRect.isValid() || d->scaledSize.isValid() || d->scaledClipRect.isValid());
       
   151         QSize finalSize = d->defaultSize;
       
   152         QRectF bounds;
       
   153         if (xform && !d->defaultSize.isEmpty()) {
       
   154             bounds = QRectF(QPointF(0,0), QSizeF(d->defaultSize));
       
   155             QPoint tr1, tr2;
       
   156             QSizeF sc(1, 1);
       
   157             if (d->clipRect.isValid()) {
       
   158                 tr1 = -d->clipRect.topLeft();
       
   159                 finalSize = d->clipRect.size();
   107             }
   160             }
       
   161             if (d->scaledSize.isValid()) {
       
   162                 sc = QSizeF(qreal(d->scaledSize.width()) / finalSize.width(),
       
   163                             qreal(d->scaledSize.height()) / finalSize.height());
       
   164                 finalSize = d->scaledSize;
       
   165             }
       
   166             if (d->scaledClipRect.isValid()) {
       
   167                 tr2 = -d->scaledClipRect.topLeft();
       
   168                 finalSize = d->scaledClipRect.size();
       
   169             }
       
   170             QTransform t;
       
   171             t.translate(tr2.x(), tr2.y());
       
   172             t.scale(sc.width(), sc.height());
       
   173             t.translate(tr1.x(), tr1.y());
       
   174             bounds = t.mapRect(bounds);
   108         }
   175         }
   109         if (device->atEnd())
   176         *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied);
   110             break;
   177         if (!finalSize.isEmpty()) {
   111         device->seek(device->pos()-4);
   178             image->fill(d->backColor.rgba());
   112     }
       
   113     device->seek(pos);
       
   114     return false;
       
   115 }
       
   116 
       
   117 QSvgIOHandler::QSvgIOHandler()
       
   118     : d(new QSvgIOHandlerPrivate())
       
   119 {
       
   120 
       
   121 }
       
   122 
       
   123 
       
   124 QSvgIOHandler::~QSvgIOHandler()
       
   125 {
       
   126     delete d;
       
   127 }
       
   128 
       
   129 
       
   130 bool QSvgIOHandler::canRead() const
       
   131 {
       
   132     return QSvgIOHandlerPrivate::findSvgTag(device());
       
   133 }
       
   134 
       
   135 
       
   136 QByteArray QSvgIOHandler::name() const
       
   137 {
       
   138     return "svg";
       
   139 }
       
   140 
       
   141 
       
   142 bool QSvgIOHandler::read(QImage *image)
       
   143 {
       
   144     if (d->load(device())) {
       
   145         *image = QImage(d->currentSize, QImage::Format_ARGB32_Premultiplied);
       
   146         if (!d->currentSize.isEmpty()) {
       
   147             image->fill(0x00000000);
       
   148             QPainter p(image);
   179             QPainter p(image);
   149             d->r->render(&p);
   180             d->r.render(&p, bounds);
   150             p.end();
   181             p.end();
   151         }
   182         }
       
   183         d->readDone = true;
   152         return true;
   184         return true;
   153     }
   185     }
   154 
   186 
   155     return false;
   187     return false;
   156 }
   188 }
   164         break;
   196         break;
   165     case Size:
   197     case Size:
   166         d->load(device());
   198         d->load(device());
   167         return d->defaultSize;
   199         return d->defaultSize;
   168         break;
   200         break;
       
   201     case ClipRect:
       
   202         return d->clipRect;
       
   203         break;
   169     case ScaledSize:
   204     case ScaledSize:
   170         return d->currentSize;
   205         return d->scaledSize;
       
   206         break;
       
   207     case ScaledClipRect:
       
   208         return d->scaledClipRect;
       
   209         break;
       
   210     case BackgroundColor:
       
   211         return d->backColor;
   171         break;
   212         break;
   172     default:
   213     default:
   173         break;
   214         break;
   174     }
   215     }
   175     return QVariant();
   216     return QVariant();
   177 
   218 
   178 
   219 
   179 void QSvgIOHandler::setOption(ImageOption option, const QVariant & value)
   220 void QSvgIOHandler::setOption(ImageOption option, const QVariant & value)
   180 {
   221 {
   181     switch(option) {
   222     switch(option) {
   182     case Size:
   223     case ClipRect:
   183         d->defaultSize = value.toSize();
   224         d->clipRect = value.toRect();
   184         d->currentSize = value.toSize();
       
   185         break;
   225         break;
   186     case ScaledSize:
   226     case ScaledSize:
   187         d->currentSize = value.toSize();
   227         d->scaledSize = value.toSize();
       
   228         break;
       
   229     case ScaledClipRect:
       
   230         d->scaledClipRect = value.toRect();
       
   231         break;
       
   232     case BackgroundColor:
       
   233         d->backColor = value.value<QColor>();
   188         break;
   234         break;
   189     default:
   235     default:
   190         break;
   236         break;
   191     }
   237     }
   192 }
   238 }
   196 {
   242 {
   197     switch(option)
   243     switch(option)
   198     {
   244     {
   199     case ImageFormat:
   245     case ImageFormat:
   200     case Size:
   246     case Size:
       
   247     case ClipRect:
   201     case ScaledSize:
   248     case ScaledSize:
       
   249     case ScaledClipRect:
       
   250     case BackgroundColor:
   202         return true;
   251         return true;
   203     default:
   252     default:
   204         break;
   253         break;
   205     }
   254     }
   206     return false;
   255     return false;
   207 }
   256 }
   208 
   257 
       
   258 
   209 bool QSvgIOHandler::canRead(QIODevice *device)
   259 bool QSvgIOHandler::canRead(QIODevice *device)
   210 {
   260 {
   211     return QSvgIOHandlerPrivate::findSvgTag(device);
   261     QByteArray buf = device->peek(8);
       
   262     return buf.startsWith("\x1f\x8b") || buf.contains("<?xml") || buf.contains("<svg");
   212 }
   263 }
   213 
   264 
   214 QT_END_NAMESPACE
   265 QT_END_NAMESPACE
   215 
   266 
   216 #endif // QT_NO_SVGRENDERER
   267 #endif // QT_NO_SVGRENDERER