blob: 4f8a9aac97499dd3530e8e6e388f6a3e0ba0bea4 [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkPDFDevice.h"
18
19#include "SkColor.h"
20#include "SkPaint.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000021#include "SkPath.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000022#include "SkPDFImage.h"
23#include "SkPDFGraphicState.h"
24#include "SkPDFTypes.h"
25#include "SkPDFStream.h"
26#include "SkRect.h"
27#include "SkString.h"
28
vandebo@chromium.orga5180862010-10-26 19:48:49 +000029#define NOT_IMPLEMENTED(condition, assert) \
30 do { \
31 if (condition) { \
32 fprintf(stderr, "NOT_IMPLEMENTED: " #condition "\n"); \
33 SkASSERT(!assert); \
34 } \
35 } while(0)
36
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000037// Utility functions
38
39namespace {
40
41SkString toPDFColor(SkColor color) {
42 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere.
43 SkScalar colorMax = SkIntToScalar(0xFF);
44 SkString result;
vandebo@chromium.orga5180862010-10-26 19:48:49 +000045 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetR(color)),
46 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000047 result.append(" ");
vandebo@chromium.orga5180862010-10-26 19:48:49 +000048 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetG(color)),
49 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000050 result.append(" ");
vandebo@chromium.orga5180862010-10-26 19:48:49 +000051 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetB(color)),
52 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000053 result.append(" ");
54 return result;
55}
56
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000057} // namespace
58
59////////////////////////////////////////////////////////////////////////////////
60
61SkDevice* SkPDFDeviceFactory::newDevice(SkBitmap::Config config,
62 int width, int height,
63 bool isOpaque, bool isForLayer) {
64 return SkNEW_ARGS(SkPDFDevice, (width, height));
65}
66
67SkPDFDevice::SkPDFDevice(int width, int height)
68 : fWidth(width),
69 fHeight(height),
70 fCurrentColor(0),
71 fCurrentTextScaleX(SK_Scalar1) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000072 fContent.append("q\n");
73 fCurTransform.reset();
74 fActiveTransform.reset();
75}
76
77SkPDFDevice::~SkPDFDevice() {
78 fGraphicStateResources.unrefAll();
79 fXObjectResources.unrefAll();
80}
81
82void SkPDFDevice::setMatrixClip(const SkMatrix& matrix,
83 const SkRegion& region) {
84 // TODO(vandebo) handle clipping
85 setTransform(matrix);
86 fCurTransform = matrix;
87}
88
89void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
90 setNoTransform();
91
92 SkPaint newPaint = paint;
93 newPaint.setStyle(SkPaint::kFill_Style);
94 updateGSFromPaint(newPaint, NULL);
95
96 SkRect all = SkRect::MakeWH(width() + 1, height() + 1);
97 drawRect(d, all, newPaint);
98 setTransform(fCurTransform);
99}
100
101void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
102 size_t count, const SkPoint* points,
103 const SkPaint& paint) {
104 if (count == 0)
105 return;
106
107 switch (mode) {
108 case SkCanvas::kPolygon_PointMode:
109 updateGSFromPaint(paint, NULL);
110 moveTo(points[0].fX, points[0].fY);
111 for (size_t i = 1; i < count; i++)
112 appendLine(points[i].fX, points[i].fY);
113 strokePath();
114 break;
115 case SkCanvas::kLines_PointMode:
116 updateGSFromPaint(paint, NULL);
117 for (size_t i = 0; i < count/2; i++) {
118 moveTo(points[i * 2].fX, points[i * 2].fY);
119 appendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY);
120 strokePath();
121 }
122 break;
123 case SkCanvas::kPoints_PointMode:
124 if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
125 updateGSFromPaint(paint, NULL);
126 for (size_t i = 0; i < count; i++) {
127 moveTo(points[i].fX, points[i].fY);
128 strokePath();
129 }
130 } else {
131 // PDF won't draw a single point with square/butt caps because
132 // the orientation is ambiguous. Draw a rectangle instead.
133 SkPaint newPaint = paint;
134 newPaint.setStyle(SkPaint::kFill_Style);
135 SkScalar strokeWidth = paint.getStrokeWidth();
136 SkScalar halfStroke = strokeWidth * SK_ScalarHalf;
137 for (size_t i = 0; i < count; i++) {
138 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY,
139 0, 0);
140 r.inset(-halfStroke, -halfStroke);
141 drawRect(d, r, newPaint);
142 }
143 }
144 break;
145 default:
146 SkASSERT(false);
147 }
148}
149
150void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
151 const SkPaint& paint) {
152 if (paint.getPathEffect()) {
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000153 // Create a path for the rectangle and apply the path effect to it.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000154 SkPath path;
155 path.addRect(r);
156 paint.getFillPath(path, &path);
157
158 SkPaint no_effect_paint(paint);
159 SkSafeUnref(no_effect_paint.setPathEffect(NULL));
160 drawPath(d, path, no_effect_paint);
161 return;
162 }
163 updateGSFromPaint(paint, NULL);
164
165 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
166 SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop;
167 appendRectangle(r.fLeft, bottom, r.width(), r.height());
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000168 paintPath(paint.getStyle(), SkPath::kWinding_FillType);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000169}
170
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000171void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path,
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000172 const SkPaint& paint) {
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000173 if (paint.getPathEffect()) {
174 // Apply the path effect to path and draw it that way.
175 SkPath no_effect_path;
176 paint.getFillPath(path, &no_effect_path);
177
178 SkPaint no_effect_paint(paint);
179 SkSafeUnref(no_effect_paint.setPathEffect(NULL));
180 drawPath(d, no_effect_path, no_effect_paint);
181 return;
182 }
183 updateGSFromPaint(paint, NULL);
184
185 SkPoint args[4];
186 SkPath::Iter iter(path, false);
187 for (SkPath::Verb verb = iter.next(args);
188 verb != SkPath::kDone_Verb;
189 verb = iter.next(args)) {
190 // args gets all the points, even the implicit first point.
191 switch (verb) {
192 case SkPath::kMove_Verb:
193 moveTo(args[0].fX, args[0].fY);
194 break;
195 case SkPath::kLine_Verb:
196 appendLine(args[1].fX, args[1].fY);
197 break;
198 case SkPath::kQuad_Verb: {
199 // Convert quad to cubic (degree elevation). http://goo.gl/vS4i
200 const SkScalar three = SkIntToScalar(3);
201 args[1].scale(SkIntToScalar(2));
202 SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three);
203 SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three);
204 SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three);
205 SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three);
206 appendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY);
207 break;
208 }
209 case SkPath::kCubic_Verb:
210 appendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
211 args[3].fX, args[3].fY);
212 break;
213 case SkPath::kClose_Verb:
214 closePath();
215 break;
216 case SkPath::kDone_Verb:
217 break;
218 default:
219 SkASSERT(false);
220 break;
221 }
222 }
223 paintPath(paint.getStyle(), path.getFillType());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000224}
225
226void SkPDFDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
227 const SkMatrix& matrix, const SkPaint& paint) {
228 SkMatrix scaled;
229 // Adjust for origin flip.
230 scaled.setScale(1, -1);
231 scaled.postTranslate(0, 1);
232 scaled.postConcat(fCurTransform);
233 // Scale the image up from 1x1 to WxH.
234 scaled.postScale(bitmap.width(), bitmap.height());
235 scaled.postConcat(matrix);
236 internalDrawBitmap(scaled, bitmap, paint);
237}
238
239void SkPDFDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
240 int x, int y, const SkPaint& paint) {
241 SkMatrix scaled;
242 // Adjust for origin flip.
243 scaled.setScale(1, -1);
244 scaled.postTranslate(0, 1);
245 // Scale the image up from 1x1 to WxH.
246 scaled.postScale(bitmap.width(), -bitmap.height());
247 scaled.postTranslate(x, y);
248 internalDrawBitmap(scaled, bitmap, paint);
249}
250
251void SkPDFDevice::drawText(const SkDraw&, const void* text, size_t len,
252 SkScalar x, SkScalar y, const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000253 NOT_IMPLEMENTED("drawText", true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000254}
255
256void SkPDFDevice::drawPosText(const SkDraw&, const void* text, size_t len,
257 const SkScalar pos[], SkScalar constY,
258 int scalarsPerPos, const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000259 NOT_IMPLEMENTED("drawPosText", false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000260}
261
262void SkPDFDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
263 const SkPath& path, const SkMatrix* matrix,
264 const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000265 NOT_IMPLEMENTED("drawTextOnPath", true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000266}
267
268void SkPDFDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
269 int vertexCount, const SkPoint verts[],
270 const SkPoint texs[], const SkColor colors[],
271 SkXfermode* xmode, const uint16_t indices[],
272 int indexCount, const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000273 NOT_IMPLEMENTED("drawVerticies", true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000274}
275
276void SkPDFDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y,
277 const SkPaint&) {
278 SkASSERT(false);
279}
280
281const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
282 if (fResourceDict.get() == NULL) {
283 fResourceDict = new SkPDFDict;
284 fResourceDict->unref(); // SkRefPtr and new both took a reference.
285
286 if (fGraphicStateResources.count()) {
287 SkRefPtr<SkPDFDict> extGState = new SkPDFDict();
288 extGState->unref(); // SkRefPtr and new both took a reference.
289 for (int i = 0; i < fGraphicStateResources.count(); i++) {
290 SkString nameString("G");
291 nameString.appendS32(i);
292 SkRefPtr<SkPDFName> name = new SkPDFName(nameString);
293 name->unref(); // SkRefPtr and new both took a reference.
294 SkRefPtr<SkPDFObjRef> gsRef =
295 new SkPDFObjRef(fGraphicStateResources[i]);
296 gsRef->unref(); // SkRefPtr and new both took a reference.
297 extGState->insert(name.get(), gsRef.get());
298 }
299 fResourceDict->insert("ExtGState", extGState.get());
300 }
301
302 if (fXObjectResources.count()) {
303 SkRefPtr<SkPDFDict> xObjects = new SkPDFDict();
304 xObjects->unref(); // SkRefPtr and new both took a reference.
305 for (int i = 0; i < fXObjectResources.count(); i++) {
306 SkString nameString("X");
307 nameString.appendS32(i);
308 SkRefPtr<SkPDFName> name = new SkPDFName(nameString);
309 name->unref(); // SkRefPtr and new both took a reference.
310 SkRefPtr<SkPDFObjRef> xObjRef =
311 new SkPDFObjRef(fXObjectResources[i]);
312 xObjRef->unref(); // SkRefPtr and new both took a reference.
313 xObjects->insert(name.get(), xObjRef.get());
314 }
315 fResourceDict->insert("XObject", xObjects.get());
316 }
317 }
318 return fResourceDict;
319}
320
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000321void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
322 resourceList->setReserve(resourceList->count() +
323 fGraphicStateResources.count() +
324 fXObjectResources.count());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000325 for (int i = 0; i < fGraphicStateResources.count(); i++) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000326 resourceList->push(fGraphicStateResources[i]);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000327 fGraphicStateResources[i]->ref();
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000328 fGraphicStateResources[i]->getResources(resourceList);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000329 }
330 for (int i = 0; i < fXObjectResources.count(); i++) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000331 resourceList->push(fXObjectResources[i]);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000332 fXObjectResources[i]->ref();
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000333 fXObjectResources[i]->getResources(resourceList);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000334 }
335}
336
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000337SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000338 SkRefPtr<SkPDFInt> zero = new SkPDFInt(0);
339 zero->unref(); // SkRefPtr and new both took a reference.
340 SkRefPtr<SkPDFInt> width = new SkPDFInt(fWidth);
341 width->unref(); // SkRefPtr and new both took a reference.
342 SkRefPtr<SkPDFInt> height = new SkPDFInt(fHeight);
343 height->unref(); // SkRefPtr and new both took a reference.
344 SkRefPtr<SkPDFArray> mediaBox = new SkPDFArray();
345 mediaBox->unref(); // SkRefPtr and new both took a reference.
346 mediaBox->reserve(4);
347 mediaBox->append(zero.get());
348 mediaBox->append(zero.get());
349 mediaBox->append(width.get());
350 mediaBox->append(height.get());
351 return mediaBox;
352}
353
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000354SkString SkPDFDevice::content(bool flipOrigin) const {
355 SkString result;
356 // Scale and translate to move the origin from the lower left to the
357 // upper left.
358 if (flipOrigin)
359 result.printf("1 0 0 -1 0 %d cm\n", fHeight);
360 result.append(fContent);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000361 result.append("Q");
362 return result;
363}
364
365// Private
366
367// TODO(vandebo) handle these cases.
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000368#define PAINTCHECK(x,y) NOT_IMPLEMENTED(newPaint.x() y, false)
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000369
370void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint,
371 SkString* textStateUpdate) {
372 PAINTCHECK(getXfermode, != NULL);
373 PAINTCHECK(getPathEffect, != NULL);
374 PAINTCHECK(getMaskFilter, != NULL);
375 PAINTCHECK(getShader, != NULL);
376 PAINTCHECK(getColorFilter, != NULL);
377 PAINTCHECK(isFakeBoldText, == true);
378 PAINTCHECK(isUnderlineText, == true);
379 PAINTCHECK(isStrikeThruText, == true);
380 PAINTCHECK(getTextSkewX, != 0);
381
382 SkRefPtr<SkPDFGraphicState> newGraphicState =
383 SkPDFGraphicState::getGraphicStateForPaint(newPaint);
384 newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref.
385 // newGraphicState has been canonicalized so we can directly compare
386 // pointers.
387 if (fCurrentGraphicState.get() != newGraphicState.get()) {
388 int resourceIndex = fGraphicStateResources.find(newGraphicState.get());
389 if (resourceIndex < 0) {
390 resourceIndex = fGraphicStateResources.count();
391 fGraphicStateResources.push(newGraphicState.get());
392 newGraphicState->ref();
393 }
394 fContent.append("/G");
395 fContent.appendS32(resourceIndex);
396 fContent.append(" gs\n");
397 fCurrentGraphicState = newGraphicState;
398 }
399
400 SkColor newColor = newPaint.getColor();
401 newColor = SkColorSetA(newColor, 0xFF);
402 if (fCurrentColor != newColor) {
403 SkString colorString = toPDFColor(newColor);
404 fContent.append(colorString);
405 fContent.append("RG ");
406 fContent.append(colorString);
407 fContent.append("rg\n");
408 fCurrentColor = newColor;
409 }
410
411 if (textStateUpdate != NULL &&
412 fCurrentTextScaleX != newPaint.getTextScaleX()) {
413 SkScalar scale = newPaint.getTextScaleX();
414 SkScalar pdfScale = scale * 100;
415 textStateUpdate->appendScalar(pdfScale);
416 textStateUpdate->append(" Tz\n");
417 fCurrentTextScaleX = scale;
418 }
419}
420
421void SkPDFDevice::moveTo(SkScalar x, SkScalar y) {
422 fContent.appendScalar(x);
423 fContent.append(" ");
424 fContent.appendScalar(y);
425 fContent.append(" m\n");
426}
427
428void SkPDFDevice::appendLine(SkScalar x, SkScalar y) {
429 fContent.appendScalar(x);
430 fContent.append(" ");
431 fContent.appendScalar(y);
432 fContent.append(" l\n");
433}
434
435void SkPDFDevice::appendCubic(SkScalar ctl1X, SkScalar ctl1Y,
436 SkScalar ctl2X, SkScalar ctl2Y,
437 SkScalar dstX, SkScalar dstY) {
438 SkString cmd("y\n");
439 fContent.appendScalar(ctl1X);
440 fContent.append(" ");
441 fContent.appendScalar(ctl1Y);
442 fContent.append(" ");
443 if (ctl2X != dstX || ctl2Y != dstY) {
444 cmd.set("c\n");
445 fContent.appendScalar(ctl2X);
446 fContent.append(" ");
447 fContent.appendScalar(ctl2Y);
448 fContent.append(" ");
449 }
450 fContent.appendScalar(dstX);
451 fContent.append(" ");
452 fContent.appendScalar(dstY);
453 fContent.append(cmd);
454}
455
456void SkPDFDevice::appendRectangle(SkScalar x, SkScalar y,
457 SkScalar w, SkScalar h) {
458 fContent.appendScalar(x);
459 fContent.append(" ");
460 fContent.appendScalar(y);
461 fContent.append(" ");
462 fContent.appendScalar(w);
463 fContent.append(" ");
464 fContent.appendScalar(h);
465 fContent.append(" re\n");
466}
467
468void SkPDFDevice::closePath() {
469 fContent.append("h\n");
470}
471
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000472void SkPDFDevice::paintPath(SkPaint::Style style, SkPath::FillType fill) {
473 if (style == SkPaint::kFill_Style)
474 fContent.append("f");
475 else if (style == SkPaint::kStrokeAndFill_Style)
476 fContent.append("B");
477 else if (style == SkPaint::kStroke_Style)
478 fContent.append("S");
479
480 if (style != SkPaint::kStroke_Style) {
481 // Not supported yet.
482 NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
483 NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
484 if (fill == SkPath::kEvenOdd_FillType)
485 fContent.append("*");
486 }
487 fContent.append("\n");
488}
489
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000490void SkPDFDevice::strokePath() {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000491 paintPath(SkPaint::kStroke_Style, SkPath::kWinding_FillType);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000492}
493
494void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
495 const SkBitmap& bitmap,
496 const SkPaint& paint) {
497 setTransform(matrix);
498 SkPDFImage* image = new SkPDFImage(bitmap, paint);
499 fXObjectResources.push(image); // Transfer reference.
500 fContent.append("/X");
501 fContent.appendS32(fXObjectResources.count() - 1);
502 fContent.append(" Do\n");
503 setTransform(fCurTransform);
504}
505
506void SkPDFDevice::setTransform(const SkMatrix& m) {
507 setNoTransform();
508 applyTransform(m);
509}
510
511void SkPDFDevice::setNoTransform() {
512 if (fActiveTransform.getType() == SkMatrix::kIdentity_Mask)
513 return;
514 fContent.append("Q q "); // Restore the default transform and save it.
515 fCurrentGraphicState = NULL;
516 fActiveTransform.reset();
517}
518
519void SkPDFDevice::applyTempTransform(const SkMatrix& m) {
520 fContent.append("q ");
521 applyTransform(m);
522}
523
524void SkPDFDevice::removeTempTransform() {
525 fContent.append("Q\n");
526 fActiveTransform = fCurTransform;
527}
528
529void SkPDFDevice::applyTransform(const SkMatrix& m) {
530 if (m == fActiveTransform)
531 return;
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000532 SkScalar transform[6];
533 SkAssertResult(m.pdfTransform(transform));
534 for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
535 fContent.appendScalar(transform[i]);
536 fContent.append(" ");
537 }
538 fContent.append("cm\n");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000539 fActiveTransform = m;
540}