15e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org/*
25e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org * Copyright 2013 Google Inc.
35e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org *
45e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
55e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org * found in the LICENSE file.
65e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org */
75e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
85e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org#include "SkPDFDeviceFlattener.h"
95e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org#include "SkDraw.h"
105e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
115e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgstatic SkISize SkSizeToISize(const SkSize& size) {
125e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    return SkISize::Make(SkScalarRoundToInt(size.width()), SkScalarRoundToInt(size.height()));
135e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
145e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
155e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgSkPDFDeviceFlattener::SkPDFDeviceFlattener(const SkSize& pageSize, const SkRect* trimBox)
165e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org            : SkPDFDevice(SkSizeToISize(pageSize),
175e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                          SkSizeToISize(pageSize),
185e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                          SkMatrix::I()) {
195e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    // TODO(edisonn): store the trimbox on emit.
205e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
215e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
225e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgSkPDFDeviceFlattener::~SkPDFDeviceFlattener() {
235e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
245e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
255e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgstatic void flattenPaint(const SkDraw& d, SkPaint* paint) {
265e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (paint->getShader()) {
275970f625e96cdc007c563ae72f343ae0d71719a1commit-bot@chromium.org        SkAutoTUnref<SkShader> lms(SkShader::CreateLocalMatrixShader(paint->getShader(),
285970f625e96cdc007c563ae72f343ae0d71719a1commit-bot@chromium.org                                                                     *d.fMatrix));
295970f625e96cdc007c563ae72f343ae0d71719a1commit-bot@chromium.org        paint->setShader(lms);
305e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
315e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
325e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
335e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
345e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                      size_t count, const SkPoint points[],
355e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                      const SkPaint& paint) {
365e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (!mustFlatten(d)) {
375e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        INHERITED::drawPoints(d, mode, count, points, paint);
385e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
395e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
405e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
415e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPaint paintFlatten(paint);
425e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    flattenPaint(d, &paintFlatten);
435e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
445e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPoint* flattenedPoints = SkNEW_ARRAY(SkPoint, count);
45a4662865e37a2ca95b5e3379072f6a274acc8ac8robertphillips@google.com    d.fMatrix->mapPoints(flattenedPoints, points, SkToS32(count));
465e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkDraw draw(d);
475e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkMatrix identity = SkMatrix::I();
485e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    draw.fMatrix = &identity;
495e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawPoints(draw, mode, count, flattenedPoints, paintFlatten);
505e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkDELETE_ARRAY(flattenedPoints);
515e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
525e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
535e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) {
545e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (!mustFlatten(d)) {
555e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        INHERITED::drawRect(d, r, paint);
565e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
575e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
585e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
595e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPath path;
605e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    path.addRect(r);
615e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    path.transform(*d.fMatrix);
625e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkDraw draw(d);
635e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkMatrix matrix = SkMatrix::I();
645e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    draw.fMatrix = &matrix;
655e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
665e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPaint paintFlatten(paint);
675e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    flattenPaint(d, &paintFlatten);
685e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
695e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawPath(draw, path, paintFlatten, NULL, true);
705e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
715e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
725e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawPath(const SkDraw& d, const SkPath& origPath,
735e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                    const SkPaint& paint, const SkMatrix* prePathMatrix,
745e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                    bool pathIsMutable) {
755e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (!mustFlatten(d) && !(prePathMatrix && prePathMatrix->hasPerspective())) {
765e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        INHERITED::drawPath(d, origPath, paint, prePathMatrix, pathIsMutable);
775e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
785e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
795e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
805e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPath* pathPtr = (SkPath*)&origPath;
815e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPath tmpPath;
825e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
835e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (!pathIsMutable) {
845e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        tmpPath = origPath;
855e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        pathPtr = &tmpPath;
865e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
875e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
885e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (prePathMatrix) {
895e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        pathPtr->transform(*prePathMatrix);
905e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
915e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
925e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkPaint paintFlatten(paint);
935e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    flattenPaint(d, &paintFlatten);
945e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
955e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    bool fill = paintFlatten.getFillPath(*pathPtr, &tmpPath);
965e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkDEBUGCODE(pathPtr = (SkPath*)0x12345678);  // Don't use pathPtr after this point.
975e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
985e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    paintFlatten.setPathEffect(NULL);
995e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (fill) {
1005e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        paintFlatten.setStyle(SkPaint::kFill_Style);
1015e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    } else {
1025e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        paintFlatten.setStyle(SkPaint::kStroke_Style);
1035e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        paintFlatten.setStrokeWidth(0);
1045e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
1055e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1065e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    tmpPath.transform(*d.fMatrix);
1075e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1085e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkDraw draw(d);
1095e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    SkMatrix matrix = SkMatrix::I();
1105e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    draw.fMatrix = &matrix;
1115e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1125e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawPath(draw, tmpPath, paintFlatten, NULL, true);
1135e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
1145e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1155e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawText(const SkDraw& d, const void* text, size_t len,
1165e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                    SkScalar x, SkScalar y, const SkPaint& paint) {
1175e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (mustPathText(d, paint)) {
1185e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        d.drawText_asPaths((const char*)text, len, x, y, paint);
1195e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
1205e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
1215e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1225e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawText(d, text, len, x, y, paint);
1235e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
1245e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1255e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawPosText(const SkDraw& d, const void* text, size_t len,
1265e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                       const SkScalar pos[], SkScalar constY,
1275e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                       int scalarsPerPos, const SkPaint& paint) {
1285e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (mustPathText(d, paint)) {
1295e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        d.drawPosText_asPaths((const char*)text, len, pos, constY, scalarsPerPos, paint);
1305e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
1315e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
1325e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawPosText(d, text, len, pos, constY,scalarsPerPos, paint);
1335e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
1345e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1355e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgvoid SkPDFDeviceFlattener::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
1365e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                          const SkPath& path, const SkMatrix* matrix,
1375e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org                                          const SkPaint& paint) {
1385e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    if (mustPathText(d, paint) || (matrix && matrix->hasPerspective())) {
1395e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        d.drawTextOnPath((const char*)text, len, path, matrix, paint);
1405e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org        return;
1415e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    }
1425e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    INHERITED::drawTextOnPath(d, text, len, path, matrix, paint);
1435e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
1445e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1455e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgbool SkPDFDeviceFlattener::mustFlatten(const SkDraw& d) const {
1465e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    // TODO(edisonn): testability, add flag to force return true.
1475e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    return d.fMatrix->hasPerspective();
1485e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
1495e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org
1505e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.orgbool SkPDFDeviceFlattener::mustPathText(const SkDraw& d, const SkPaint&) {
1515e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    // TODO(edisonn): testability, add flag to force return true.
1525e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    // TODO(edisonn): TBD: How to flatten MaskFilter.
1535e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org    return d.fMatrix->hasPerspective();
1545e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org}
155