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