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