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 } |