1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkPDFDeviceFlattener.h"
9 #include "SkDraw.h"
10
SkSizeToISize(const SkSize & size)11 static SkISize SkSizeToISize(const SkSize& size) {
12 return SkISize::Make(SkScalarRoundToInt(size.width()), SkScalarRoundToInt(size.height()));
13 }
14
SkPDFDeviceFlattener(const SkSize & pageSize,const SkRect * trimBox)15 SkPDFDeviceFlattener::SkPDFDeviceFlattener(const SkSize& pageSize, const SkRect* trimBox)
16 : SkPDFDevice(SkSizeToISize(pageSize),
17 SkSizeToISize(pageSize),
18 SkMatrix::I()) {
19 // TODO(edisonn): store the trimbox on emit.
20 }
21
~SkPDFDeviceFlattener()22 SkPDFDeviceFlattener::~SkPDFDeviceFlattener() {
23 }
24
flattenPaint(const SkDraw & d,SkPaint * paint)25 static void flattenPaint(const SkDraw& d, SkPaint* paint) {
26 if (paint->getShader()) {
27 SkAutoTUnref<SkShader> lms(SkShader::CreateLocalMatrixShader(paint->getShader(),
28 *d.fMatrix));
29 paint->setShader(lms);
30 }
31 }
32
drawPoints(const SkDraw & d,SkCanvas::PointMode mode,size_t count,const SkPoint points[],const SkPaint & paint)33 void SkPDFDeviceFlattener::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
34 size_t count, const SkPoint points[],
35 const SkPaint& paint) {
36 if (!mustFlatten(d)) {
37 INHERITED::drawPoints(d, mode, count, points, paint);
38 return;
39 }
40
41 SkPaint paintFlatten(paint);
42 flattenPaint(d, &paintFlatten);
43
44 SkPoint* flattenedPoints = SkNEW_ARRAY(SkPoint, count);
45 d.fMatrix->mapPoints(flattenedPoints, points, SkToS32(count));
46 SkDraw draw(d);
47 SkMatrix identity = SkMatrix::I();
48 draw.fMatrix = &identity;
49 INHERITED::drawPoints(draw, mode, count, flattenedPoints, paintFlatten);
50 SkDELETE_ARRAY(flattenedPoints);
51 }
52
drawRect(const SkDraw & d,const SkRect & r,const SkPaint & paint)53 void SkPDFDeviceFlattener::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) {
54 if (!mustFlatten(d)) {
55 INHERITED::drawRect(d, r, paint);
56 return;
57 }
58
59 SkPath path;
60 path.addRect(r);
61 path.transform(*d.fMatrix);
62 SkDraw draw(d);
63 SkMatrix matrix = SkMatrix::I();
64 draw.fMatrix = &matrix;
65
66 SkPaint paintFlatten(paint);
67 flattenPaint(d, &paintFlatten);
68
69 INHERITED::drawPath(draw, path, paintFlatten, NULL, true);
70 }
71
drawPath(const SkDraw & d,const SkPath & origPath,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)72 void SkPDFDeviceFlattener::drawPath(const SkDraw& d, const SkPath& origPath,
73 const SkPaint& paint, const SkMatrix* prePathMatrix,
74 bool pathIsMutable) {
75 if (!mustFlatten(d) && !(prePathMatrix && prePathMatrix->hasPerspective())) {
76 INHERITED::drawPath(d, origPath, paint, prePathMatrix, pathIsMutable);
77 return;
78 }
79
80 SkPath* pathPtr = (SkPath*)&origPath;
81 SkPath tmpPath;
82
83 if (!pathIsMutable) {
84 tmpPath = origPath;
85 pathPtr = &tmpPath;
86 }
87
88 if (prePathMatrix) {
89 pathPtr->transform(*prePathMatrix);
90 }
91
92 SkPaint paintFlatten(paint);
93 flattenPaint(d, &paintFlatten);
94
95 bool fill = paintFlatten.getFillPath(*pathPtr, &tmpPath);
96 SkDEBUGCODE(pathPtr = (SkPath*)0x12345678); // Don't use pathPtr after this point.
97
98 paintFlatten.setPathEffect(NULL);
99 if (fill) {
100 paintFlatten.setStyle(SkPaint::kFill_Style);
101 } else {
102 paintFlatten.setStyle(SkPaint::kStroke_Style);
103 paintFlatten.setStrokeWidth(0);
104 }
105
106 tmpPath.transform(*d.fMatrix);
107
108 SkDraw draw(d);
109 SkMatrix matrix = SkMatrix::I();
110 draw.fMatrix = &matrix;
111
112 INHERITED::drawPath(draw, tmpPath, paintFlatten, NULL, true);
113 }
114
drawText(const SkDraw & d,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)115 void SkPDFDeviceFlattener::drawText(const SkDraw& d, const void* text, size_t len,
116 SkScalar x, SkScalar y, const SkPaint& paint) {
117 if (mustPathText(d, paint)) {
118 d.drawText_asPaths((const char*)text, len, x, y, paint);
119 return;
120 }
121
122 INHERITED::drawText(d, text, len, x, y, paint);
123 }
124
drawPosText(const SkDraw & d,const void * text,size_t len,const SkScalar pos[],SkScalar constY,int scalarsPerPos,const SkPaint & paint)125 void SkPDFDeviceFlattener::drawPosText(const SkDraw& d, const void* text, size_t len,
126 const SkScalar pos[], SkScalar constY,
127 int scalarsPerPos, const SkPaint& paint) {
128 if (mustPathText(d, paint)) {
129 d.drawPosText_asPaths((const char*)text, len, pos, constY, scalarsPerPos, paint);
130 return;
131 }
132 INHERITED::drawPosText(d, text, len, pos, constY,scalarsPerPos, paint);
133 }
134
drawTextOnPath(const SkDraw & d,const void * text,size_t len,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)135 void SkPDFDeviceFlattener::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
136 const SkPath& path, const SkMatrix* matrix,
137 const SkPaint& paint) {
138 if (mustPathText(d, paint) || (matrix && matrix->hasPerspective())) {
139 d.drawTextOnPath((const char*)text, len, path, matrix, paint);
140 return;
141 }
142 INHERITED::drawTextOnPath(d, text, len, path, matrix, paint);
143 }
144
mustFlatten(const SkDraw & d) const145 bool SkPDFDeviceFlattener::mustFlatten(const SkDraw& d) const {
146 // TODO(edisonn): testability, add flag to force return true.
147 return d.fMatrix->hasPerspective();
148 }
149
mustPathText(const SkDraw & d,const SkPaint &)150 bool SkPDFDeviceFlattener::mustPathText(const SkDraw& d, const SkPaint&) {
151 // TODO(edisonn): testability, add flag to force return true.
152 // TODO(edisonn): TBD: How to flatten MaskFilter.
153 return d.fMatrix->hasPerspective();
154 }
155