blob: c0224829f5332239c1da85b52f9e05a4e9f5e6f8 [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00002 * Copyright (C) 2011 Google Inc.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00003 *
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"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000020#include "SkGlyphCache.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000021#include "SkPaint.h"
vandebo@chromium.orga5180862010-10-26 19:48:49 +000022#include "SkPath.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000023#include "SkPDFImage.h"
24#include "SkPDFGraphicState.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000025#include "SkPDFFont.h"
vandebo@chromium.orgeb6c7592010-10-26 19:54:45 +000026#include "SkPDFFormXObject.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000027#include "SkPDFTypes.h"
28#include "SkPDFStream.h"
29#include "SkRect.h"
30#include "SkString.h"
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000031#include "SkTextFormatParams.h"
32#include "SkTypeface.h"
33#include "SkTypes.h"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000034
vandebo@chromium.orga5180862010-10-26 19:48:49 +000035#define NOT_IMPLEMENTED(condition, assert) \
36 do { \
37 if (condition) { \
38 fprintf(stderr, "NOT_IMPLEMENTED: " #condition "\n"); \
vandebo@chromium.orgfb697e72011-02-01 01:04:00 +000039 SkDEBUGCODE(SkASSERT(!assert);) \
vandebo@chromium.orga5180862010-10-26 19:48:49 +000040 } \
41 } while(0)
42
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000043// Utility functions
44
45namespace {
46
47SkString toPDFColor(SkColor color) {
48 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere.
49 SkScalar colorMax = SkIntToScalar(0xFF);
50 SkString result;
vandebo@chromium.orga5180862010-10-26 19:48:49 +000051 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetR(color)),
52 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000053 result.append(" ");
vandebo@chromium.orga5180862010-10-26 19:48:49 +000054 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetG(color)),
55 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000056 result.append(" ");
vandebo@chromium.orga5180862010-10-26 19:48:49 +000057 result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetB(color)),
58 colorMax));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000059 result.append(" ");
60 return result;
61}
62
vandebo@chromium.org28be72b2010-11-11 21:37:00 +000063SkPaint calculateTextPaint(const SkPaint& paint) {
64 SkPaint result = paint;
65 if (result.isFakeBoldText()) {
66 SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
67 kStdFakeBoldInterpKeys,
68 kStdFakeBoldInterpValues,
69 kStdFakeBoldInterpLength);
70 SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
71 if (result.getStyle() == SkPaint::kFill_Style)
72 result.setStyle(SkPaint::kStrokeAndFill_Style);
73 else
74 width += result.getStrokeWidth();
75 result.setStrokeWidth(width);
76 }
77 return result;
78}
79
80// Stolen from measure_text in SkDraw.cpp and then tweaked.
81void alignText(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
82 const uint16_t* glyphs, size_t len, SkScalar* x, SkScalar* y,
83 SkScalar* width) {
84 if (paint.getTextAlign() == SkPaint::kLeft_Align && width == NULL)
85 return;
86
87 SkMatrix ident;
88 ident.reset();
89 SkAutoGlyphCache autoCache(paint, &ident);
90 SkGlyphCache* cache = autoCache.getCache();
91
92 const char* start = (char*)glyphs;
93 const char* stop = (char*)(glyphs + len);
94 SkFixed xAdv = 0, yAdv = 0;
95
96 // TODO(vandebo) This probably needs to take kerning into account.
97 while (start < stop) {
98 const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
99 xAdv += glyph.fAdvanceX;
100 yAdv += glyph.fAdvanceY;
101 };
102 if (width)
103 *width = SkFixedToScalar(xAdv);
104 if (paint.getTextAlign() == SkPaint::kLeft_Align)
105 return;
106
107 SkScalar xAdj = SkFixedToScalar(xAdv);
108 SkScalar yAdj = SkFixedToScalar(yAdv);
109 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
110 xAdj = SkScalarHalf(xAdj);
111 yAdj = SkScalarHalf(yAdj);
112 }
113 *x = *x - xAdj;
114 *y = *y - yAdj;
115}
116
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000117} // namespace
118
119////////////////////////////////////////////////////////////////////////////////
120
reed@android.comf2b98d62010-12-20 18:26:13 +0000121SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
122 int width, int height, bool isOpaque,
123 bool /*isForLayer*/) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000124 return SkNEW_ARGS(SkPDFDevice, (width, height));
125}
126
reed@android.comf2b98d62010-12-20 18:26:13 +0000127static inline SkBitmap makeABitmap(int width, int height) {
128 SkBitmap bitmap;
129 bitmap.setConfig(SkBitmap::kNo_Config, width, height);
130 return bitmap;
131}
132
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000133SkPDFDevice::SkPDFDevice(int width, int height)
reed@google.com07700442010-12-20 19:46:07 +0000134 : SkDevice(NULL, makeABitmap(width, height), false),
135 fWidth(width),
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000136 fHeight(height),
reed@google.com07700442010-12-20 19:46:07 +0000137 fGraphicStackIndex(0) {
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000138 fGraphicStack[0].fColor = SK_ColorBLACK;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000139 fGraphicStack[0].fTextSize = SK_ScalarNaN; // This has no default value.
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000140 fGraphicStack[0].fTextScaleX = SK_Scalar1;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000141 fGraphicStack[0].fTextFill = SkPaint::kFill_Style;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000142 fGraphicStack[0].fFont = NULL;
143 fGraphicStack[0].fGraphicState = NULL;
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000144 fGraphicStack[0].fClip.setRect(0,0, width, height);
145 fGraphicStack[0].fTransform.reset();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000146}
147
148SkPDFDevice::~SkPDFDevice() {
149 fGraphicStateResources.unrefAll();
150 fXObjectResources.unrefAll();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000151 fFontResources.unrefAll();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000152}
153
154void SkPDFDevice::setMatrixClip(const SkMatrix& matrix,
155 const SkRegion& region) {
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000156 // See the comment in the header file above GraphicStackEntry.
157 if (region != fGraphicStack[fGraphicStackIndex].fClip) {
158 while (fGraphicStackIndex > 0)
159 popGS();
160 pushGS();
161
162 SkPath clipPath;
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000163 if (region.getBoundaryPath(&clipPath)) {
164 emitPath(clipPath);
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000165
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000166 SkPath::FillType clipFill = clipPath.getFillType();
167 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType,
168 false);
169 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType,
170 false);
171 if (clipFill == SkPath::kEvenOdd_FillType)
172 fContent.append("W* n ");
173 else
174 fContent.append("W n ");
175 }
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000176
177 fGraphicStack[fGraphicStackIndex].fClip = region;
178 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000179 setTransform(matrix);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000180}
181
182void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000183 SkMatrix identityTransform;
184 identityTransform.reset();
185 SkMatrix curTransform = setTransform(identityTransform);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000186
187 SkPaint newPaint = paint;
188 newPaint.setStyle(SkPaint::kFill_Style);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000189 updateGSFromPaint(newPaint, false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000190
191 SkRect all = SkRect::MakeWH(width() + 1, height() + 1);
192 drawRect(d, all, newPaint);
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000193 setTransform(curTransform);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000194}
195
196void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
197 size_t count, const SkPoint* points,
198 const SkPaint& paint) {
199 if (count == 0)
200 return;
201
202 switch (mode) {
203 case SkCanvas::kPolygon_PointMode:
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000204 updateGSFromPaint(paint, false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000205 moveTo(points[0].fX, points[0].fY);
206 for (size_t i = 1; i < count; i++)
207 appendLine(points[i].fX, points[i].fY);
208 strokePath();
209 break;
210 case SkCanvas::kLines_PointMode:
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000211 updateGSFromPaint(paint, false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000212 for (size_t i = 0; i < count/2; i++) {
213 moveTo(points[i * 2].fX, points[i * 2].fY);
214 appendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY);
215 strokePath();
216 }
217 break;
218 case SkCanvas::kPoints_PointMode:
219 if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000220 updateGSFromPaint(paint, false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000221 for (size_t i = 0; i < count; i++) {
222 moveTo(points[i].fX, points[i].fY);
223 strokePath();
224 }
225 } else {
226 // PDF won't draw a single point with square/butt caps because
227 // the orientation is ambiguous. Draw a rectangle instead.
228 SkPaint newPaint = paint;
229 newPaint.setStyle(SkPaint::kFill_Style);
230 SkScalar strokeWidth = paint.getStrokeWidth();
231 SkScalar halfStroke = strokeWidth * SK_ScalarHalf;
232 for (size_t i = 0; i < count; i++) {
233 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY,
234 0, 0);
235 r.inset(-halfStroke, -halfStroke);
236 drawRect(d, r, newPaint);
237 }
238 }
239 break;
240 default:
241 SkASSERT(false);
242 }
243}
244
245void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
246 const SkPaint& paint) {
247 if (paint.getPathEffect()) {
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000248 // Create a path for the rectangle and apply the path effect to it.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000249 SkPath path;
250 path.addRect(r);
251 paint.getFillPath(path, &path);
252
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000253 SkPaint noEffectPaint(paint);
254 SkSafeUnref(noEffectPaint.setPathEffect(NULL));
vandebo@chromium.org02cc5aa2011-01-25 22:06:29 +0000255 drawPath(d, path, noEffectPaint, NULL, true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000256 return;
257 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000258 updateGSFromPaint(paint, false);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000259
260 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
261 SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop;
262 appendRectangle(r.fLeft, bottom, r.width(), r.height());
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000263 paintPath(paint.getStyle(), SkPath::kWinding_FillType);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000264}
265
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000266void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path,
vandebo@chromium.org02cc5aa2011-01-25 22:06:29 +0000267 const SkPaint& paint, const SkMatrix* prePathMatrix,
268 bool pathIsMutable) {
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000269 NOT_IMPLEMENTED(prePathMatrix != NULL, true);
vandebo@chromium.org02cc5aa2011-01-25 22:06:29 +0000270
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000271 if (paint.getPathEffect()) {
272 // Apply the path effect to path and draw it that way.
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000273 SkPath noEffectPath;
274 paint.getFillPath(path, &noEffectPath);
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000275
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000276 SkPaint noEffectPaint(paint);
277 SkSafeUnref(noEffectPaint.setPathEffect(NULL));
vandebo@chromium.org02cc5aa2011-01-25 22:06:29 +0000278 drawPath(d, noEffectPath, noEffectPaint, NULL, true);
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000279 return;
280 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000281 updateGSFromPaint(paint, false);
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000282
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000283 emitPath(path);
vandebo@chromium.org7d71f7f2010-10-26 19:51:44 +0000284 paintPath(paint.getStyle(), path.getFillType());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000285}
286
287void SkPDFDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
reed@android.comf2b98d62010-12-20 18:26:13 +0000288 const SkIRect* srcRect,
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000289 const SkMatrix& matrix, const SkPaint& paint) {
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000290 SkMatrix transform = matrix;
291 transform.postConcat(fGraphicStack[fGraphicStackIndex].fTransform);
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000292 internalDrawBitmap(transform, bitmap, srcRect, paint);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000293}
294
295void SkPDFDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
296 int x, int y, const SkPaint& paint) {
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000297 SkMatrix matrix;
298 matrix.setTranslate(x, y);
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000299 internalDrawBitmap(matrix, bitmap, NULL, paint);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000300}
301
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000302void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000303 SkScalar x, SkScalar y, const SkPaint& paint) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000304 SkPaint textPaint = calculateTextPaint(paint);
305 updateGSFromPaint(textPaint, true);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000306
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000307 // Make sure we have a glyph id encoding.
308 SkAutoFree glyphStorage;
309 uint16_t* glyphIDs;
310 size_t numGlyphs;
311 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
312 numGlyphs = paint.textToGlyphs(text, len, NULL);
313 glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
314 SK_MALLOC_TEMP | SK_MALLOC_THROW);
315 glyphStorage.set(glyphIDs);
316 paint.textToGlyphs(text, len, glyphIDs);
317 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
318 } else {
319 SkASSERT((len & 1) == 0);
320 numGlyphs = len / 2;
321 glyphIDs = (uint16_t*)text;
322 }
323 SkAutoFree encodedStorage(
324 sk_malloc_flags(numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW));
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000325
326 SkScalar width;
327 SkScalar* widthPtr = NULL;
328 if (textPaint.isUnderlineText() || textPaint.isStrikeThruText())
329 widthPtr = &width;
330
331 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000332 alignText(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y, widthPtr);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000333 fContent.append("BT\n");
334 setTextTransform(x, y, textPaint.getTextSkewX());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000335 size_t consumedGlyphCount = 0;
336 while (numGlyphs > consumedGlyphCount) {
337 updateFont(textPaint, glyphIDs[consumedGlyphCount]);
338 SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont;
339 size_t encodedLength = numGlyphs * 2;
340 consumedGlyphCount += font->glyphsToPDFFontEncoding(
341 glyphIDs + consumedGlyphCount, numGlyphs - consumedGlyphCount,
342 encodedStorage.get(), &encodedLength);
343 if (font->multiByteGlyphs())
344 encodedLength /= 2;
345 fContent.append(
346 SkPDFString::formatString((const uint16_t*)encodedStorage.get(),
347 encodedLength,
348 font->multiByteGlyphs()));
349 fContent.append(" Tj\n");
350 }
351 fContent.append("ET\n");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000352
353 // Draw underline and/or strikethrough if the paint has them.
354 // drawPosText() and drawTextOnPath() don't draw underline or strikethrough
355 // because the raster versions don't. Use paint instead of textPaint
356 // because we may have changed strokeWidth to do fakeBold text.
357 if (paint.isUnderlineText() || paint.isStrikeThruText()) {
358 SkScalar textSize = paint.getTextSize();
359 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
360
361 if (paint.isUnderlineText()) {
362 SkScalar top = SkScalarMulAdd(textSize, kStdUnderline_Offset, y);
363 SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
364 drawRect(d, r, paint);
365 }
366 if (paint.isStrikeThruText()) {
367 SkScalar top = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, y);
368 SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
369 drawRect(d, r, paint);
370 }
371 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000372}
373
374void SkPDFDevice::drawPosText(const SkDraw&, const void* text, size_t len,
375 const SkScalar pos[], SkScalar constY,
376 int scalarsPerPos, const SkPaint& paint) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000377 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
378 SkPaint textPaint = calculateTextPaint(paint);
379 updateGSFromPaint(textPaint, true);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000380
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000381 // Make sure we have a glyph id encoding.
382 SkAutoFree glyphStorage;
383 uint16_t* glyphIDs;
384 size_t numGlyphs;
385 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
386 numGlyphs = paint.textToGlyphs(text, len, NULL);
387 glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
388 SK_MALLOC_TEMP | SK_MALLOC_THROW);
389 glyphStorage.set(glyphIDs);
390 paint.textToGlyphs(text, len, glyphIDs);
391 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
392 } else {
393 SkASSERT((len & 1) == 0);
394 numGlyphs = len / 2;
395 glyphIDs = (uint16_t*)text;
396 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000397
398 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
399 fContent.append("BT\n");
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000400 updateFont(textPaint, glyphIDs[0]);
401 for (size_t i = 0; i < numGlyphs; i++) {
402 SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont;
403 uint16_t encodedValue;
404 size_t encodedLength = 2;
405 if (font->glyphsToPDFFontEncoding(glyphIDs + i, 1, &encodedValue,
406 &encodedLength) == 0) {
407 updateFont(textPaint, glyphIDs[i]);
408 i--;
409 continue;
410 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000411 SkScalar x = pos[i * scalarsPerPos];
412 SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000413 alignText(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000414 setTextTransform(x, y, textPaint.getTextSkewX());
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000415 fContent.append(SkPDFString::formatString(&encodedValue, 1,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000416 font->multiByteGlyphs()));
417 fContent.append(" Tj\n");
418 }
419 fContent.append("ET\n");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000420}
421
422void SkPDFDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
423 const SkPath& path, const SkMatrix* matrix,
424 const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000425 NOT_IMPLEMENTED("drawTextOnPath", true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000426}
427
428void SkPDFDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
429 int vertexCount, const SkPoint verts[],
430 const SkPoint texs[], const SkColor colors[],
431 SkXfermode* xmode, const uint16_t indices[],
432 int indexCount, const SkPaint& paint) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000433 NOT_IMPLEMENTED("drawVerticies", true);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000434}
435
vandebo@chromium.orgeb6c7592010-10-26 19:54:45 +0000436void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
437 const SkPaint& paint) {
438 if ((device->getDeviceCapabilities() & kVector_Capability) == 0) {
439 // If we somehow get a raster device, do what our parent would do.
440 SkDevice::drawDevice(d, device, x, y, paint);
441 return;
442 }
443
444 // Assume that a vector capable device means that it's a PDF Device.
445 // TODO(vandebo) handle the paint (alpha and compositing mode).
446 SkMatrix matrix;
447 matrix.setTranslate(x, y);
448 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
449
450 SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice, matrix);
451 fXObjectResources.push(xobject); // Transfer reference.
452 fContent.append("/X");
453 fContent.appendS32(fXObjectResources.count() - 1);
454 fContent.append(" Do\n");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000455}
456
457const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
458 if (fResourceDict.get() == NULL) {
459 fResourceDict = new SkPDFDict;
460 fResourceDict->unref(); // SkRefPtr and new both took a reference.
461
462 if (fGraphicStateResources.count()) {
463 SkRefPtr<SkPDFDict> extGState = new SkPDFDict();
464 extGState->unref(); // SkRefPtr and new both took a reference.
465 for (int i = 0; i < fGraphicStateResources.count(); i++) {
466 SkString nameString("G");
467 nameString.appendS32(i);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000468 extGState->insert(
469 nameString.c_str(),
470 new SkPDFObjRef(fGraphicStateResources[i]))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000471 }
472 fResourceDict->insert("ExtGState", extGState.get());
473 }
474
475 if (fXObjectResources.count()) {
476 SkRefPtr<SkPDFDict> xObjects = new SkPDFDict();
477 xObjects->unref(); // SkRefPtr and new both took a reference.
478 for (int i = 0; i < fXObjectResources.count(); i++) {
479 SkString nameString("X");
480 nameString.appendS32(i);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000481 xObjects->insert(
482 nameString.c_str(),
483 new SkPDFObjRef(fXObjectResources[i]))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000484 }
485 fResourceDict->insert("XObject", xObjects.get());
486 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000487
488 if (fFontResources.count()) {
489 SkRefPtr<SkPDFDict> fonts = new SkPDFDict();
490 fonts->unref(); // SkRefPtr and new both took a reference.
491 for (int i = 0; i < fFontResources.count(); i++) {
492 SkString nameString("F");
493 nameString.appendS32(i);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000494 fonts->insert(nameString.c_str(),
495 new SkPDFObjRef(fFontResources[i]))->unref();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000496 }
497 fResourceDict->insert("Font", fonts.get());
498 }
499
500 // For compatibility, add all proc sets (only used for output to PS
501 // devices).
502 const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
503 SkRefPtr<SkPDFArray> procSets = new SkPDFArray();
504 procSets->unref(); // SkRefPtr and new both took a reference.
505 procSets->reserve(SK_ARRAY_COUNT(procs));
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000506 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++)
507 procSets->append(new SkPDFName(procs[i]))->unref();
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000508 fResourceDict->insert("ProcSet", procSets.get());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000509 }
510 return fResourceDict;
511}
512
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000513void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
514 resourceList->setReserve(resourceList->count() +
515 fGraphicStateResources.count() +
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000516 fXObjectResources.count() +
517 fFontResources.count());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000518 for (int i = 0; i < fGraphicStateResources.count(); i++) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000519 resourceList->push(fGraphicStateResources[i]);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000520 fGraphicStateResources[i]->ref();
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000521 fGraphicStateResources[i]->getResources(resourceList);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000522 }
523 for (int i = 0; i < fXObjectResources.count(); i++) {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000524 resourceList->push(fXObjectResources[i]);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000525 fXObjectResources[i]->ref();
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000526 fXObjectResources[i]->getResources(resourceList);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000527 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000528 for (int i = 0; i < fFontResources.count(); i++) {
529 resourceList->push(fFontResources[i]);
530 fFontResources[i]->ref();
531 fFontResources[i]->getResources(resourceList);
532 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000533}
534
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000535SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000536 SkRefPtr<SkPDFInt> zero = new SkPDFInt(0);
537 zero->unref(); // SkRefPtr and new both took a reference.
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000538
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000539 SkRefPtr<SkPDFArray> mediaBox = new SkPDFArray();
540 mediaBox->unref(); // SkRefPtr and new both took a reference.
541 mediaBox->reserve(4);
542 mediaBox->append(zero.get());
543 mediaBox->append(zero.get());
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000544 mediaBox->append(new SkPDFInt(fWidth))->unref();
545 mediaBox->append(new SkPDFInt(fHeight))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000546 return mediaBox;
547}
548
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000549SkString SkPDFDevice::content(bool flipOrigin) const {
550 SkString result;
551 // Scale and translate to move the origin from the lower left to the
552 // upper left.
553 if (flipOrigin)
554 result.printf("1 0 0 -1 0 %d cm\n", fHeight);
555 result.append(fContent);
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000556 for (int i = 0; i < fGraphicStackIndex; i++)
557 result.append("Q\n");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000558 return result;
559}
560
561// Private
562
563// TODO(vandebo) handle these cases.
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000564#define PAINTCHECK(x,y) NOT_IMPLEMENTED(newPaint.x() y, false)
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000565
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000566void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint, bool forText) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000567 PAINTCHECK(getXfermode, != NULL);
568 PAINTCHECK(getPathEffect, != NULL);
569 PAINTCHECK(getMaskFilter, != NULL);
570 PAINTCHECK(getShader, != NULL);
571 PAINTCHECK(getColorFilter, != NULL);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000572
573 SkRefPtr<SkPDFGraphicState> newGraphicState =
574 SkPDFGraphicState::getGraphicStateForPaint(newPaint);
575 newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref.
576 // newGraphicState has been canonicalized so we can directly compare
577 // pointers.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000578 if (fGraphicStack[fGraphicStackIndex].fGraphicState !=
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000579 newGraphicState.get()) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000580 int resourceIndex = fGraphicStateResources.find(newGraphicState.get());
581 if (resourceIndex < 0) {
582 resourceIndex = fGraphicStateResources.count();
583 fGraphicStateResources.push(newGraphicState.get());
584 newGraphicState->ref();
585 }
586 fContent.append("/G");
587 fContent.appendS32(resourceIndex);
588 fContent.append(" gs\n");
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000589 fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000590 }
591
592 SkColor newColor = newPaint.getColor();
593 newColor = SkColorSetA(newColor, 0xFF);
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000594 if (fGraphicStack[fGraphicStackIndex].fColor != newColor) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000595 SkString colorString = toPDFColor(newColor);
596 fContent.append(colorString);
597 fContent.append("RG ");
598 fContent.append(colorString);
599 fContent.append("rg\n");
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000600 fGraphicStack[fGraphicStackIndex].fColor = newColor;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000601 }
602
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000603 if (forText) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000604 if (fGraphicStack[fGraphicStackIndex].fTextScaleX !=
605 newPaint.getTextScaleX()) {
606 SkScalar scale = newPaint.getTextScaleX();
607 SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100));
608 fContent.appendScalar(pdfScale);
609 fContent.append(" Tz\n");
610 fGraphicStack[fGraphicStackIndex].fTextScaleX = scale;
611 }
612
613 if (fGraphicStack[fGraphicStackIndex].fTextFill !=
614 newPaint.getStyle()) {
615 SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
616 SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
617 enum_must_match_value);
618 SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
619 enum_must_match_value);
620 fContent.appendS32(newPaint.getStyle());
621 fContent.append(" Tr\n");
622 fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle();
623 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000624 }
625}
626
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000627void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) {
628 uint32_t fontID = SkTypeface::UniqueID(paint.getTypeface());
629 if (fGraphicStack[fGraphicStackIndex].fTextSize != paint.getTextSize() ||
630 fGraphicStack[fGraphicStackIndex].fFont == NULL ||
631 fGraphicStack[fGraphicStackIndex].fFont->fontID() != fontID ||
632 !fGraphicStack[fGraphicStackIndex].fFont->hasGlyph(glyphID)) {
633 int fontIndex = getFontResourceIndex(fontID, glyphID);
634 fContent.append("/F");
635 fContent.appendS32(fontIndex);
636 fContent.append(" ");
637 fContent.appendScalar(paint.getTextSize());
638 fContent.append(" Tf\n");
639 fGraphicStack[fGraphicStackIndex].fTextSize = paint.getTextSize();
640 fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex];
641 }
642}
643
644
645int SkPDFDevice::getFontResourceIndex(uint32_t fontID, uint16_t glyphID) {
646 SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(fontID, glyphID);
647 newFont->unref(); // getFontResource and SkRefPtr both took a ref.
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000648 int resourceIndex = fFontResources.find(newFont.get());
649 if (resourceIndex < 0) {
650 resourceIndex = fFontResources.count();
651 fFontResources.push(newFont.get());
652 newFont->ref();
653 }
654 return resourceIndex;
655}
656
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000657void SkPDFDevice::moveTo(SkScalar x, SkScalar y) {
658 fContent.appendScalar(x);
659 fContent.append(" ");
660 fContent.appendScalar(y);
661 fContent.append(" m\n");
662}
663
664void SkPDFDevice::appendLine(SkScalar x, SkScalar y) {
665 fContent.appendScalar(x);
666 fContent.append(" ");
667 fContent.appendScalar(y);
668 fContent.append(" l\n");
669}
670
671void SkPDFDevice::appendCubic(SkScalar ctl1X, SkScalar ctl1Y,
672 SkScalar ctl2X, SkScalar ctl2Y,
673 SkScalar dstX, SkScalar dstY) {
674 SkString cmd("y\n");
675 fContent.appendScalar(ctl1X);
676 fContent.append(" ");
677 fContent.appendScalar(ctl1Y);
678 fContent.append(" ");
679 if (ctl2X != dstX || ctl2Y != dstY) {
680 cmd.set("c\n");
681 fContent.appendScalar(ctl2X);
682 fContent.append(" ");
683 fContent.appendScalar(ctl2Y);
684 fContent.append(" ");
685 }
686 fContent.appendScalar(dstX);
687 fContent.append(" ");
688 fContent.appendScalar(dstY);
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000689 fContent.append(" ");
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000690 fContent.append(cmd);
691}
692
693void SkPDFDevice::appendRectangle(SkScalar x, SkScalar y,
694 SkScalar w, SkScalar h) {
695 fContent.appendScalar(x);
696 fContent.append(" ");
697 fContent.appendScalar(y);
698 fContent.append(" ");
699 fContent.appendScalar(w);
700 fContent.append(" ");
701 fContent.appendScalar(h);
702 fContent.append(" re\n");
703}
704
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000705void SkPDFDevice::emitPath(const SkPath& path) {
706 SkPoint args[4];
707 SkPath::Iter iter(path, false);
708 for (SkPath::Verb verb = iter.next(args);
709 verb != SkPath::kDone_Verb;
710 verb = iter.next(args)) {
711 // args gets all the points, even the implicit first point.
712 switch (verb) {
713 case SkPath::kMove_Verb:
714 moveTo(args[0].fX, args[0].fY);
715 break;
716 case SkPath::kLine_Verb:
717 appendLine(args[1].fX, args[1].fY);
718 break;
719 case SkPath::kQuad_Verb: {
720 // Convert quad to cubic (degree elevation). http://goo.gl/vS4i
721 const SkScalar three = SkIntToScalar(3);
722 args[1].scale(SkIntToScalar(2));
723 SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three);
724 SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three);
725 SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three);
726 SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three);
727 appendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY);
728 break;
729 }
730 case SkPath::kCubic_Verb:
731 appendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
732 args[3].fX, args[3].fY);
733 break;
734 case SkPath::kClose_Verb:
735 closePath();
736 break;
737 case SkPath::kDone_Verb:
738 break;
739 default:
740 SkASSERT(false);
741 break;
742 }
743 }
744}
745
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000746void SkPDFDevice::closePath() {
747 fContent.append("h\n");
748}
749
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000750void SkPDFDevice::paintPath(SkPaint::Style style, SkPath::FillType fill) {
751 if (style == SkPaint::kFill_Style)
752 fContent.append("f");
753 else if (style == SkPaint::kStrokeAndFill_Style)
754 fContent.append("B");
755 else if (style == SkPaint::kStroke_Style)
756 fContent.append("S");
757
758 if (style != SkPaint::kStroke_Style) {
759 // Not supported yet.
760 NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
761 NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
762 if (fill == SkPath::kEvenOdd_FillType)
763 fContent.append("*");
764 }
765 fContent.append("\n");
766}
767
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000768void SkPDFDevice::strokePath() {
vandebo@chromium.orga5180862010-10-26 19:48:49 +0000769 paintPath(SkPaint::kStroke_Style, SkPath::kWinding_FillType);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000770}
771
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000772void SkPDFDevice::pushGS() {
773 SkASSERT(fGraphicStackIndex < 2);
774 fContent.append("q\n");
775 fGraphicStackIndex++;
776 fGraphicStack[fGraphicStackIndex] = fGraphicStack[fGraphicStackIndex - 1];
777}
778
779void SkPDFDevice::popGS() {
780 SkASSERT(fGraphicStackIndex > 0);
781 fContent.append("Q\n");
782 fGraphicStackIndex--;
783}
784
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000785void SkPDFDevice::setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX) {
786 // Flip the text about the x-axis to account for origin swap and include
787 // the passed parameters.
788 fContent.append("1 0 ");
789 fContent.appendScalar(0 - textSkewX);
790 fContent.append(" -1 ");
791 fContent.appendScalar(x);
792 fContent.append(" ");
793 fContent.appendScalar(y);
794 fContent.append(" Tm\n");
795}
796
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000797void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
798 const SkBitmap& bitmap,
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000799 const SkIRect* srcRect,
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000800 const SkPaint& paint) {
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000801 SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height());
802 if (srcRect && !subset.intersect(*srcRect))
803 return;
804
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +0000805 SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, paint);
806 if (!image)
807 return;
808
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000809 SkMatrix scaled;
810 // Adjust for origin flip.
811 scaled.setScale(1, -1);
812 scaled.postTranslate(0, 1);
813 // Scale the image up from 1x1 to WxH.
vandebo@chromium.orgbefebb82011-01-29 01:38:50 +0000814 scaled.postScale(subset.width(), subset.height());
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000815 scaled.postConcat(matrix);
816 SkMatrix curTransform = setTransform(scaled);
817
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000818 fXObjectResources.push(image); // Transfer reference.
819 fContent.append("/X");
820 fContent.appendS32(fXObjectResources.count() - 1);
821 fContent.append(" Do\n");
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000822 setTransform(curTransform);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000823}
824
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000825SkMatrix SkPDFDevice::setTransform(const SkMatrix& m) {
826 SkMatrix old = fGraphicStack[fGraphicStackIndex].fTransform;
827 if (old == m)
828 return old;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000829
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000830 if (old.getType() != SkMatrix::kIdentity_Mask) {
831 SkASSERT(fGraphicStackIndex > 0);
832 SkASSERT(fGraphicStack[fGraphicStackIndex - 1].fTransform.getType() ==
833 SkMatrix::kIdentity_Mask);
834 SkASSERT(fGraphicStack[fGraphicStackIndex].fClip ==
835 fGraphicStack[fGraphicStackIndex - 1].fClip);
836 popGS();
837 }
838 if (m.getType() == SkMatrix::kIdentity_Mask)
839 return old;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000840
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000841 if (fGraphicStackIndex == 0 || fGraphicStack[fGraphicStackIndex].fClip !=
842 fGraphicStack[fGraphicStackIndex - 1].fClip)
843 pushGS();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000844
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000845 SkScalar transform[6];
846 SkAssertResult(m.pdfTransform(transform));
847 for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
848 fContent.appendScalar(transform[i]);
849 fContent.append(" ");
850 }
851 fContent.append("cm\n");
vandebo@chromium.org7e2ff7c2010-11-03 23:55:28 +0000852 fGraphicStack[fGraphicStackIndex].fTransform = m;
853
854 return old;
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000855}