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