/*
* 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();
}