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 11 static SkISize SkSizeToISize(const SkSize& size) { 12 return SkISize::Make(SkScalarRoundToInt(size.width()), SkScalarRoundToInt(size.height())); 13 } 14 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 22 SkPDFDeviceFlattener::~SkPDFDeviceFlattener() { 23 } 24 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 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 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 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 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 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 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 145 bool SkPDFDeviceFlattener::mustFlatten(const SkDraw& d) const { 146 // TODO(edisonn): testability, add flag to force return true. 147 return d.fMatrix->hasPerspective(); 148 } 149 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