Home | History | Annotate | Download | only in pdf
      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