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