/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkPDFDeviceFlattener.h" #include "SkDraw.h" static SkISize SkSizeToISize(const SkSize& size) { return SkISize::Make(SkScalarRoundToInt(size.width()), SkScalarRoundToInt(size.height())); } SkPDFDeviceFlattener::SkPDFDeviceFlattener(const SkSize& pageSize, const SkRect* trimBox) : SkPDFDevice(SkSizeToISize(pageSize), SkSizeToISize(pageSize), SkMatrix::I()) { // TODO(edisonn): store the trimbox on emit. } SkPDFDeviceFlattener::~SkPDFDeviceFlattener() { } static void flattenPaint(const SkDraw& d, SkPaint* paint) { if (paint->getShader()) { SkMatrix local = paint->getShader()->getLocalMatrix(); local.preConcat(*d.fMatrix); paint->getShader()->setLocalMatrix(local); } } void SkPDFDeviceFlattener::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, size_t count, const SkPoint points[], const SkPaint& paint) { if (!mustFlatten(d)) { INHERITED::drawPoints(d, mode, count, points, paint); return; } SkPaint paintFlatten(paint); flattenPaint(d, &paintFlatten); SkPoint* flattenedPoints = SkNEW_ARRAY(SkPoint, count); d.fMatrix->mapPoints(flattenedPoints, points, SkToS32(count)); SkDraw draw(d); SkMatrix identity = SkMatrix::I(); draw.fMatrix = &identity; INHERITED::drawPoints(draw, mode, count, flattenedPoints, paintFlatten); SkDELETE_ARRAY(flattenedPoints); } void SkPDFDeviceFlattener::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) { if (!mustFlatten(d)) { INHERITED::drawRect(d, r, paint); return; } SkPath path; path.addRect(r); path.transform(*d.fMatrix); SkDraw draw(d); SkMatrix matrix = SkMatrix::I(); draw.fMatrix = &matrix; SkPaint paintFlatten(paint); flattenPaint(d, &paintFlatten); INHERITED::drawPath(draw, path, paintFlatten, NULL, true); } void SkPDFDeviceFlattener::drawPath(const SkDraw& d, const SkPath& origPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { if (!mustFlatten(d) && !(prePathMatrix && prePathMatrix->hasPerspective())) { INHERITED::drawPath(d, origPath, paint, prePathMatrix, pathIsMutable); return; } SkPath* pathPtr = (SkPath*)&origPath; SkPath tmpPath; if (!pathIsMutable) { tmpPath = origPath; pathPtr = &tmpPath; } if (prePathMatrix) { pathPtr->transform(*prePathMatrix); } SkPaint paintFlatten(paint); flattenPaint(d, &paintFlatten); bool fill = paintFlatten.getFillPath(*pathPtr, &tmpPath); SkDEBUGCODE(pathPtr = (SkPath*)0x12345678); // Don't use pathPtr after this point. paintFlatten.setPathEffect(NULL); if (fill) { paintFlatten.setStyle(SkPaint::kFill_Style); } else { paintFlatten.setStyle(SkPaint::kStroke_Style); paintFlatten.setStrokeWidth(0); } tmpPath.transform(*d.fMatrix); SkDraw draw(d); SkMatrix matrix = SkMatrix::I(); draw.fMatrix = &matrix; INHERITED::drawPath(draw, tmpPath, paintFlatten, NULL, true); } void SkPDFDeviceFlattener::drawText(const SkDraw& d, const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) { if (mustPathText(d, paint)) { d.drawText_asPaths((const char*)text, len, x, y, paint); return; } INHERITED::drawText(d, text, len, x, y, paint); } void SkPDFDeviceFlattener::drawPosText(const SkDraw& d, const void* text, size_t len, const SkScalar pos[], SkScalar constY, int scalarsPerPos, const SkPaint& paint) { if (mustPathText(d, paint)) { d.drawPosText_asPaths((const char*)text, len, pos, constY, scalarsPerPos, paint); return; } INHERITED::drawPosText(d, text, len, pos, constY,scalarsPerPos, paint); } void SkPDFDeviceFlattener::drawTextOnPath(const SkDraw& d, const void* text, size_t len, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { if (mustPathText(d, paint) || (matrix && matrix->hasPerspective())) { d.drawTextOnPath((const char*)text, len, path, matrix, paint); return; } INHERITED::drawTextOnPath(d, text, len, path, matrix, paint); } bool SkPDFDeviceFlattener::mustFlatten(const SkDraw& d) const { // TODO(edisonn): testability, add flag to force return true. return d.fMatrix->hasPerspective(); } bool SkPDFDeviceFlattener::mustPathText(const SkDraw& d, const SkPaint&) { // TODO(edisonn): testability, add flag to force return true. // TODO(edisonn): TBD: How to flatten MaskFilter. return d.fMatrix->hasPerspective(); }