aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar dandov <dandov@google.com>2014-08-12 08:34:29 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-08-12 08:34:29 -0700
commitb3c9d1c33caf325aada244204215eb790c228c12 (patch)
tree067c0017914891d0aff2b6d6163f2de1c2b20c54 /src
parent9c7695b0b59b97da933cd11014c922344a8d7654 (diff)
SkCanvas::drawPatch param SkPoint[12]
drawPatch now receives as parameter const SkPoint cubics[12] Adjusted derived classes and serialization. Ajusted GM's and benches that take into account combinations of optional parameters, the scale of the patch and 4 different types of patches. Planning on adding the extra functionality of SkPatch in another CL. BUG=skia: R=egdaniel@google.com, reed@google.com Author: dandov@google.com Review URL: https://codereview.chromium.org/463493002
Diffstat (limited to 'src')
-rw-r--r--src/core/SkBBoxRecord.cpp10
-rw-r--r--src/core/SkBBoxRecord.h4
-rw-r--r--src/core/SkCanvas.cpp17
-rw-r--r--src/core/SkDevice.cpp12
-rw-r--r--src/core/SkPatch.cpp262
-rw-r--r--src/core/SkPicturePlayback.cpp26
-rw-r--r--src/core/SkPictureRecord.cpp53
-rw-r--r--src/core/SkPictureRecord.h7
-rw-r--r--src/core/SkReadBuffer.cpp4
-rw-r--r--src/core/SkRecordDraw.cpp2
-rw-r--r--src/core/SkRecorder.cpp10
-rw-r--r--src/core/SkRecorder.h5
-rw-r--r--src/core/SkRecords.h20
-rw-r--r--src/core/SkValidatingReadBuffer.cpp11
-rw-r--r--src/core/SkValidatingReadBuffer.h1
-rw-r--r--src/pipe/SkGPipeRead.cpp26
-rw-r--r--src/pipe/SkGPipeWrite.cpp50
-rw-r--r--src/utils/SkDeferredCanvas.cpp10
-rw-r--r--src/utils/SkDumpCanvas.cpp26
-rw-r--r--src/utils/SkNWayCanvas.cpp6
-rw-r--r--src/utils/SkPatchUtils.cpp307
-rw-r--r--src/utils/SkPatchUtils.h104
-rw-r--r--src/utils/SkProxyCanvas.cpp6
23 files changed, 621 insertions, 358 deletions
diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp
index 96e6500888..69139ad54d 100644
--- a/src/core/SkBBoxRecord.cpp
+++ b/src/core/SkBBoxRecord.cpp
@@ -7,6 +7,7 @@
*/
#include "SkBBoxRecord.h"
+#include "SkPatchUtils.h"
SkBBoxRecord::~SkBBoxRecord() {
fSaveStack.deleteAll();
@@ -284,12 +285,13 @@ void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
}
}
-void SkBBoxRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
- const SkPoint* points = patch.getControlPoints();
+void SkBBoxRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
SkRect bbox;
- bbox.set(points, SkPatch::kNumCtrlPts);
+ bbox.set(cubics, SkPatchUtils::kNumCtrlPts);
if (this->transformBounds(bbox, &paint)) {
- INHERITED::drawPatch(patch, paint);
+ INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, paint);
}
}
diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h
index eafd9d465e..1d19b70054 100644
--- a/src/core/SkBBoxRecord.h
+++ b/src/core/SkBBoxRecord.h
@@ -55,7 +55,6 @@ public:
const SkColor colors[], SkXfermode* xfer,
const uint16_t indices[], int indexCount,
const SkPaint& paint) SK_OVERRIDE;
- virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
protected:
virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE;
@@ -67,6 +66,9 @@ protected:
SkScalar constY, const SkPaint&) SK_OVERRIDE;
virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
+ virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) SK_OVERRIDE;
virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
virtual void willSave() SK_OVERRIDE;
virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index c6b57396e0..240dc9ccc5 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -15,6 +15,7 @@
#include "SkDrawLooper.h"
#include "SkMetaData.h"
#include "SkPathOps.h"
+#include "SkPatchUtils.h"
#include "SkPicture.h"
#include "SkRasterClip.h"
#include "SkRRect.h"
@@ -2254,20 +2255,30 @@ void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
LOOPER_END
}
-void SkCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+ if (NULL == cubics) {
+ return;
+ }
// Since a patch is always within the convex hull of the control points, we discard it when its
// bounding rectangle is completely outside the current clip.
SkRect bounds;
- bounds.set(patch.getControlPoints(), SkPatch::kNumCtrlPts);
+ bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
if (this->quickReject(bounds)) {
return;
}
+ this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
+}
+
+void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
while (iter.next()) {
- iter.fDevice->drawPatch(iter, patch, paint);
+ iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
}
LOOPER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 6ceaffebb3..50755c94ed 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -79,15 +79,17 @@ void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
}
-void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPatch& patch, const SkPaint& paint) {
- SkPatch::VertexData data;
+void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+ SkPatchUtils::VertexData data;
- SkISize lod = SkPatchUtils::GetLevelOfDetail(patch, draw.fMatrix);
+ SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, draw.fMatrix);
// It automatically adjusts lodX and lodY in case it exceeds the number of indices.
- patch.getVertexData(&data, lod.width(), lod.height());
+ SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height());
this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
- data.fTexCoords, data.fColors, NULL, data.fIndices, data.fIndexCount, paint);
+ data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
+ paint);
}
bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
diff --git a/src/core/SkPatch.cpp b/src/core/SkPatch.cpp
deleted file mode 100644
index 4cca2bad1d..0000000000
--- a/src/core/SkPatch.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkPatch.h"
-
-#include "SkGeometry.h"
-#include "SkColorPriv.h"
-#include "SkBuffer.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Evaluator to sample the values of a cubic bezier using forward differences.
- * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
- * adding precalculated values.
- * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
- * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
- * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
- * obtaining this value (mh) we could just add this constant step to our first sampled point
- * to compute the next one.
- *
- * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
- * apply again forward differences and get linear function to which we can apply again forward
- * differences to get a constant difference. This is why we keep an array of size 4, the 0th
- * position keeps the sampled value while the next ones keep the quadratic, linear and constant
- * difference values.
- */
-
-class FwDCubicEvaluator {
-
-public:
- FwDCubicEvaluator() { }
-
- /**
- * Receives the 4 control points of the cubic bezier.
- */
- FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
- fPoints[0] = a;
- fPoints[1] = b;
- fPoints[2] = c;
- fPoints[3] = d;
-
- SkScalar cx[4], cy[4];
- SkGetCubicCoeff(fPoints, cx, cy);
- fCoefs[0].set(cx[0], cy[0]);
- fCoefs[1].set(cx[1], cy[1]);
- fCoefs[2].set(cx[2], cy[2]);
- fCoefs[3].set(cx[3], cy[3]);
-
- this->restart(1);
- }
-
- explicit FwDCubicEvaluator(SkPoint points[4]) {
- for (int i = 0; i< 4; i++) {
- fPoints[i] = points[i];
- }
-
- SkScalar cx[4], cy[4];
- SkGetCubicCoeff(fPoints, cx, cy);
- fCoefs[0].set(cx[0], cy[0]);
- fCoefs[1].set(cx[1], cy[1]);
- fCoefs[2].set(cx[2], cy[2]);
- fCoefs[3].set(cx[3], cy[3]);
-
- this->restart(1);
- }
-
- /**
- * Restarts the forward differences evaluator to the first value of t = 0.
- */
- void restart(int divisions) {
- fDivisions = divisions;
- SkScalar h = 1.f / fDivisions;
- fCurrent = 0;
- fMax = fDivisions + 1;
- fFwDiff[0] = fCoefs[3];
- SkScalar h2 = h * h;
- SkScalar h3 = h2 * h;
-
- fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
- fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
- fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
- fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
- fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
- }
-
- /**
- * Check if the evaluator is still within the range of 0<=t<=1
- */
- bool done() const {
- return fCurrent > fMax;
- }
-
- /**
- * Call next to obtain the SkPoint sampled and move to the next one.
- */
- SkPoint next() {
- SkPoint point = fFwDiff[0];
- fFwDiff[0] += fFwDiff[1];
- fFwDiff[1] += fFwDiff[2];
- fFwDiff[2] += fFwDiff[3];
- fCurrent++;
- return point;
- }
-
- const SkPoint* getCtrlPoints() const {
- return fPoints;
- }
-
-private:
- int fMax, fCurrent, fDivisions;
- SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-SkPatch::SkPatch(const SkPoint points[12], const SkColor colors[4]) {
- this->reset(points, colors);
-}
-
-static uint8_t bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
- SkScalar c11) {
- SkScalar a = c00 * (1.f - tx) + c10 * tx;
- SkScalar b = c01 * (1.f - tx) + c11 * tx;
- return uint8_t(a * (1.f - ty) + b * ty);
-}
-
-bool SkPatch::getVertexData(SkPatch::VertexData* data, int lodX, int lodY) const {
-
- if (lodX < 1 || lodY < 1) {
- return false;
- }
-
- // premultiply colors to avoid color bleeding.
- SkPMColor colors[SkPatch::kNumColors];
- for (int i = 0; i < SkPatch::kNumColors; i++) {
- colors[i] = SkPreMultiplyColor(fCornerColors[i]);
- }
-
- // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
- data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
- lodX = SkMin32(lodX, 255);
- lodY = SkMin32(lodY, 255);
- data->fIndexCount = lodX * lodY * 6;
-
- data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
- data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
- data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
- data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
-
- SkPoint pts[SkPatch::kNumPtsCubic];
- this->getBottomPoints(pts);
- FwDCubicEvaluator fBottom(pts);
- this->getTopPoints(pts);
- FwDCubicEvaluator fTop(pts);
- this->getLeftPoints(pts);
- FwDCubicEvaluator fLeft(pts);
- this->getRightPoints(pts);
- FwDCubicEvaluator fRight(pts);
-
- fBottom.restart(lodX);
- fTop.restart(lodX);
-
- SkScalar u = 0.0f;
- int stride = lodY + 1;
- for (int x = 0; x <= lodX; x++) {
- SkPoint bottom = fBottom.next(), top = fTop.next();
- fLeft.restart(lodY);
- fRight.restart(lodY);
- SkScalar v = 0.f;
- for (int y = 0; y <= lodY; y++) {
- int dataIndex = x * (lodY + 1) + y;
-
- SkPoint left = fLeft.next(), right = fRight.next();
-
- SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
- (1.0f - v) * top.y() + v * bottom.y());
- SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
- (1.0f - u) * left.y() + u * right.y());
- SkPoint s2 = SkPoint::Make(
- (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
- + u * fTop.getCtrlPoints()[3].x())
- + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
- + u * fBottom.getCtrlPoints()[3].x()),
- (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
- + u * fTop.getCtrlPoints()[3].y())
- + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
- + u * fBottom.getCtrlPoints()[3].y()));
- data->fPoints[dataIndex] = s0 + s1 - s2;
-
- uint8_t a = bilerp(u, v,
- SkScalar(SkColorGetA(colors[kTopLeft_CornerColors])),
- SkScalar(SkColorGetA(colors[kTopRight_CornerColors])),
- SkScalar(SkColorGetA(colors[kBottomLeft_CornerColors])),
- SkScalar(SkColorGetA(colors[kBottomRight_CornerColors])));
- uint8_t r = bilerp(u, v,
- SkScalar(SkColorGetR(colors[kTopLeft_CornerColors])),
- SkScalar(SkColorGetR(colors[kTopRight_CornerColors])),
- SkScalar(SkColorGetR(colors[kBottomLeft_CornerColors])),
- SkScalar(SkColorGetR(colors[kBottomRight_CornerColors])));
- uint8_t g = bilerp(u, v,
- SkScalar(SkColorGetG(colors[kTopLeft_CornerColors])),
- SkScalar(SkColorGetG(colors[kTopRight_CornerColors])),
- SkScalar(SkColorGetG(colors[kBottomLeft_CornerColors])),
- SkScalar(SkColorGetG(colors[kBottomRight_CornerColors])));
- uint8_t b = bilerp(u, v,
- SkScalar(SkColorGetB(colors[kTopLeft_CornerColors])),
- SkScalar(SkColorGetB(colors[kTopRight_CornerColors])),
- SkScalar(SkColorGetB(colors[kBottomLeft_CornerColors])),
- SkScalar(SkColorGetB(colors[kBottomRight_CornerColors])));
- data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
-
- data->fTexCoords[dataIndex] = SkPoint::Make(u, v);
-
- if(x < lodX && y < lodY) {
- int i = 6 * (x * lodY + y);
- data->fIndices[i] = x * stride + y;
- data->fIndices[i + 1] = x * stride + 1 + y;
- data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
- data->fIndices[i + 3] = data->fIndices[i];
- data->fIndices[i + 4] = data->fIndices[i + 2];
- data->fIndices[i + 5] = (x + 1) * stride + y;
- }
- v = SkScalarClampMax(v + 1.f / lodY, 1);
- }
- u = SkScalarClampMax(u + 1.f / lodX, 1);
- }
- return true;
-}
-
-size_t SkPatch::writeToMemory(void* storage) const {
- int byteCount = kNumCtrlPts * sizeof(SkPoint) + kNumColors * sizeof(SkColor);
-
- if (NULL == storage) {
- return SkAlign4(byteCount);
- }
-
- SkWBuffer buffer(storage);
-
- buffer.write(fCtrlPoints, kNumCtrlPts * sizeof(SkPoint));
- buffer.write(fCornerColors, kNumColors * sizeof(SkColor));
-
- buffer.padToAlign4();
- return buffer.pos();
-}
-
-size_t SkPatch::readFromMemory(const void* storage, size_t length) {
- SkRBufferWithSizeCheck buffer(storage, length);
-
- if (!buffer.read(fCtrlPoints, kNumCtrlPts * sizeof(SkPoint))) {
- return 0;
- }
-
- if (!buffer.read(fCornerColors, kNumColors * sizeof(SkColor))) {
- return 0;
- }
- return kNumCtrlPts * sizeof(SkPoint) + kNumColors * sizeof(SkColor);
-}
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index fd359fed89..7f3f9d75d0 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -6,6 +6,7 @@
*/
#include "SkCanvas.h"
+#include "SkPatchUtils.h"
#include "SkPictureData.h"
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
@@ -308,9 +309,28 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
break;
case DRAW_PATCH: {
const SkPaint& paint = *fPictureData->getPaint(reader);
- SkPatch patch;
- reader->readPatch(&patch);
- canvas->drawPatch(patch, paint);
+
+ const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts *
+ sizeof(SkPoint));
+ uint32_t flag = reader->readInt();
+ const SkColor* colors = NULL;
+ if (flag & DRAW_VERTICES_HAS_COLORS) {
+ colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkColor));
+ }
+ const SkPoint* texCoords = NULL;
+ if (flag & DRAW_VERTICES_HAS_TEXS) {
+ texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners *
+ sizeof(SkPoint));
+ }
+ SkAutoTUnref<SkXfermode> xfer;
+ if (flag & DRAW_VERTICES_HAS_XFER) {
+ int mode = reader->readInt();
+ if (mode < 0 || mode > SkXfermode::kLastMode) {
+ mode = SkXfermode::kModulate_Mode;
+ }
+ xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
+ }
+ canvas->drawPatch(cubics, colors, texCoords, xfer, paint);
} break;
case DRAW_PATH: {
const SkPaint& paint = *fPictureData->getPaint(reader);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index fc0b291912..7fc48e3c78 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -6,12 +6,13 @@
*/
#include "SkPictureRecord.h"
-#include "SkTSearch.h"
-#include "SkPixelRef.h"
-#include "SkRRect.h"
#include "SkBBoxHierarchy.h"
#include "SkDevice.h"
+#include "SkPatchUtils.h"
#include "SkPictureStateTree.h"
+#include "SkPixelRef.h"
+#include "SkRRect.h"
+#include "SkTSearch.h"
#define HEAP_BLOCK_SIZE 4096
@@ -1283,14 +1284,46 @@ void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
this->validate(initialOffset, size);
}
-void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
- // op + paint index + patch 12 control points + patch 4 colors
- size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
- SkPatch::kNumColors * sizeof(SkColor);
+void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
+ // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
+ size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
+ uint32_t flag = 0;
+ if (NULL != colors) {
+ flag |= DRAW_VERTICES_HAS_COLORS;
+ size += SkPatchUtils::kNumCorners * sizeof(SkColor);
+ }
+ if (NULL != texCoords) {
+ flag |= DRAW_VERTICES_HAS_TEXS;
+ size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
+ }
+ if (NULL != xmode) {
+ SkXfermode::Mode mode;
+ if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
+ flag |= DRAW_VERTICES_HAS_XFER;
+ size += kUInt32Size;
+ }
+ }
+
size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
this->addPaint(paint);
- this->addPatch(patch);
+ this->addPatch(cubics);
+ this->addInt(flag);
+
+ // write optional parameters
+ if (NULL != colors) {
+ fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
+ }
+ if (NULL != texCoords) {
+ fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
+ }
+ if (flag & DRAW_VERTICES_HAS_XFER) {
+ SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
+ xmode->asMode(&mode);
+ this->addInt(mode);
+ }
this->validate(initialOffset, size);
}
@@ -1420,8 +1453,8 @@ void SkPictureRecord::addPath(const SkPath& path) {
this->addInt(this->addPathToHeap(path));
}
-void SkPictureRecord::addPatch(const SkPatch& patch) {
- fWriter.writePatch(patch);
+void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
+ fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
}
void SkPictureRecord::addPicture(const SkPicture* picture) {
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index d0c099e040..8fd40bc230 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -58,7 +58,6 @@ public:
const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount,
const SkPaint&) SK_OVERRIDE;
- virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
virtual void drawData(const void*, size_t) SK_OVERRIDE;
virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
@@ -170,7 +169,7 @@ private:
const SkFlatData* addPaint(const SkPaint& paint) { return this->addPaintPtr(&paint); }
const SkFlatData* addPaintPtr(const SkPaint* paint);
void addFlatPaint(const SkFlatData* flatPaint);
- void addPatch(const SkPatch& patch);
+ void addPatch(const SkPoint cubics[12]);
void addPath(const SkPath& path);
void addPicture(const SkPicture* picture);
void addPoint(const SkPoint& point);
@@ -214,6 +213,10 @@ protected:
SkScalar constY, const SkPaint&) SK_OVERRIDE;
virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
+
+ virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) SK_OVERRIDE;
virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 27f2d2b3ac..43587862b9 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -148,10 +148,6 @@ void SkReadBuffer::readRegion(SkRegion* region) {
fReader.readRegion(region);
}
-void SkReadBuffer::readPatch(SkPatch* patch) {
- fReader.readPatch(patch);
-}
-
void SkReadBuffer::readPath(SkPath* path) {
fReader.readPath(path);
}
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 0e2a4701fe..8be9e005f6 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -84,7 +84,7 @@ DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
DRAW(DrawOval, drawOval(r.oval, r.paint));
DRAW(DrawPaint, drawPaint(r.paint));
DRAW(DrawPath, drawPath(r.path, r.paint));
-DRAW(DrawPatch, drawPatch(r.patch, r.paint));
+DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode.get(), r.paint));
DRAW(DrawPicture, drawPicture(r.picture, r.matrix, r.paint));
DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 6b3eac9866..327a97acdb 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -6,6 +6,7 @@
*/
#include "SkRecorder.h"
+#include "SkPatchUtils.h"
#include "SkPicture.h"
// SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
@@ -206,8 +207,13 @@ void SkRecorder::drawVertices(VertexMode vmode,
indexCount);
}
-void SkRecorder::drawPatch(const SkPatch& patch, const SkPaint& paint) {
- APPEND(DrawPatch, delay_copy(paint), delay_copy(patch));
+void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+ APPEND(DrawPatch, delay_copy(paint),
+ cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : NULL,
+ colors ? this->copy(colors, SkPatchUtils::kNumCorners) : NULL,
+ texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : NULL,
+ xmode);
}
void SkRecorder::willSave() {
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index be8924846e..2c7234ac86 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -61,7 +61,6 @@ public:
const uint16_t indices[],
int indexCount,
const SkPaint& paint) SK_OVERRIDE;
- void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
void willSave() SK_OVERRIDE;
SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SkCanvas::SaveFlags) SK_OVERRIDE;
@@ -90,6 +89,10 @@ public:
const SkPath& path,
const SkMatrix* matrix,
const SkPaint& paint) SK_OVERRIDE;
+ void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) SK_OVERRIDE;
+
void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 6aefd195c9..1efdf28b14 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -232,7 +232,7 @@ RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner);
RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
RECORD1(DrawPaint, SkPaint, paint);
RECORD2(DrawPath, SkPaint, paint, SkPath, path);
-RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
+//RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
RECORD3(DrawPicture, Optional<SkPaint>, paint, SkPictureBox, picture, Optional<SkMatrix>, matrix);
RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts);
RECORD4(DrawPosText, SkPaint, paint,
@@ -291,6 +291,24 @@ struct DrawVertices {
PODArray<uint16_t> indices;
int indexCount;
};
+
+struct DrawPatch {
+ static const Type kType = DrawPatch_Type;
+
+ DrawPatch(const SkPaint& paint, SkPoint cubics[12], SkColor colors[4],
+ SkPoint texCoords[4], SkXfermode* xmode)
+ : paint(paint)
+ , cubics(cubics)
+ , colors(colors)
+ , texCoords(texCoords)
+ , xmode(SkSafeRef(xmode)) { }
+
+ SkPaint paint;
+ PODArray<SkPoint> cubics;
+ PODArray<SkColor> colors;
+ PODArray<SkPoint> texCoords;
+ SkAutoTUnref<SkXfermode> xmode;
+};
#undef RECORD0
#undef RECORD1
diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp
index 8202149cc1..037a99465b 100644
--- a/src/core/SkValidatingReadBuffer.cpp
+++ b/src/core/SkValidatingReadBuffer.cpp
@@ -171,17 +171,6 @@ void SkValidatingReadBuffer::readPath(SkPath* path) {
}
}
-void SkValidatingReadBuffer::readPatch(SkPatch* patch) {
- size_t size = 0;
- if (!fError) {
- size = patch->readFromMemory(fReader.peek(), fReader.available());
- this->validate((SkAlign4(size) == size) && (0 != size));
- }
- if (!fError) {
- (void)this->skip(size);
- }
-}
-
bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
const uint32_t count = this->getArrayCount();
this->validate(size == count);
diff --git a/src/core/SkValidatingReadBuffer.h b/src/core/SkValidatingReadBuffer.h
index 8850a07646..5cf3abed68 100644
--- a/src/core/SkValidatingReadBuffer.h
+++ b/src/core/SkValidatingReadBuffer.h
@@ -46,7 +46,6 @@ public:
virtual void readIRect(SkIRect* rect) SK_OVERRIDE;
virtual void readRect(SkRect* rect) SK_OVERRIDE;
virtual void readRegion(SkRegion* region) SK_OVERRIDE;
- virtual void readPatch(SkPatch* patch) SK_OVERRIDE;
virtual void readPath(SkPath* path) SK_OVERRIDE;
// binary data and arrays
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 35b0a94570..35de638e05 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -21,6 +21,7 @@
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
#include "SkReadBuffer.h"
+#include "SkPatchUtils.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
#include "SkRRect.h"
@@ -406,10 +407,29 @@ static void drawDRRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
SkGPipeState* state) {
- SkPatch patch;
- reader->readPatch(&patch);
+
+ unsigned flags = DrawOp_unpackFlags(op32);
+
+ const SkPoint* cubics = skip<SkPoint>(reader, SkPatchUtils::kNumCtrlPts);
+
+ const SkColor* colors = NULL;
+ if (flags & kDrawVertices_HasColors_DrawOpFlag) {
+ colors = skip<SkColor>(reader, SkPatchUtils::kNumCorners);
+ }
+ const SkPoint* texCoords = NULL;
+ if (flags & kDrawVertices_HasTexs_DrawOpFlag) {
+ texCoords = skip<SkPoint>(reader, SkPatchUtils::kNumCorners);
+ }
+ SkAutoTUnref<SkXfermode> xfer;
+ if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
+ int mode = reader->readInt();
+ if (mode < 0 || mode > SkXfermode::kLastMode) {
+ mode = SkXfermode::kModulate_Mode;
+ }
+ xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
+ }
if (state->shouldDraw()) {
- canvas->drawPatch(patch, state->paint());
+ canvas->drawPatch(cubics, colors, texCoords, xfer, state->paint());
}
}
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index d796e8a99b..94a30a34e2 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -19,6 +19,7 @@
#include "SkMaskFilter.h"
#include "SkWriteBuffer.h"
#include "SkPaint.h"
+#include "SkPatchUtils.h"
#include "SkPathEffect.h"
#include "SkPictureFlat.h"
#include "SkRasterizer.h"
@@ -254,7 +255,6 @@ public:
const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount,
const SkPaint&) SK_OVERRIDE;
- virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
virtual void drawData(const void*, size_t) SK_OVERRIDE;
virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
@@ -283,7 +283,9 @@ protected:
SkScalar constY, const SkPaint&) SK_OVERRIDE;
virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-
+ virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) SK_OVERRIDE;
virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
@@ -1003,12 +1005,48 @@ void SkGPipeCanvas::drawVertices(VertexMode vmode, int vertexCount,
}
}
-void SkGPipeCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
NOTIFY_SETUP(this);
+
+ size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint);
+ unsigned flags = 0;
+ if (NULL != colors) {
+ flags |= kDrawVertices_HasColors_DrawOpFlag;
+ size += SkPatchUtils::kNumCorners * sizeof(SkColor);
+ }
+ if (NULL != texCoords) {
+ flags |= kDrawVertices_HasTexs_DrawOpFlag;
+ size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
+ }
+ if (NULL != xmode) {
+ SkXfermode::Mode mode;
+ if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
+ flags |= kDrawVertices_HasXfermode_DrawOpFlag;
+ size += sizeof(int32_t);
+ }
+ }
+
this->writePaint(paint);
- if (this->needOpBytes(patch.writeToMemory(NULL))) {
- this->writeOp(kDrawPatch_DrawOp);
- fWriter.writePatch(patch);
+ if (this->needOpBytes(size)) {
+ this->writeOp(kDrawPatch_DrawOp, flags, 0);
+
+ fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+
+ if (NULL != colors) {
+ fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
+ }
+
+ if (NULL != texCoords) {
+ fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
+ }
+
+ if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
+ SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
+ SkAssertResult(xmode->asMode(&mode));
+ fWriter.write32(mode);
+ }
}
}
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 128f8a564d..de3958adbc 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -224,7 +224,9 @@ protected:
SkXfermode* xmode, const uint16_t indices[],
int indexCount, const SkPaint& paint) SK_OVERRIDE
{SkASSERT(0);}
- virtual void drawPatch(const SkDraw&, const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE
+ virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) SK_OVERRIDE
{SkASSERT(0);}
virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) SK_OVERRIDE
@@ -917,9 +919,11 @@ void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
this->recordedDrawCommand();
}
-void SkDeferredCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
- this->drawingCanvas()->drawPatch(patch, paint);
+ this->drawingCanvas()->drawPatch(cubics, colors, texCoords, xmode, paint);
this->recordedDrawCommand();
}
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 946aaa33be..661f0d8860 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -9,6 +9,7 @@
#include "SkDumpCanvas.h"
#ifdef SK_DEVELOPER
+#include "SkPatchUtils.h"
#include "SkPicture.h"
#include "SkPixelRef.h"
#include "SkRRect.h"
@@ -443,17 +444,24 @@ void SkDumpCanvas::drawVertices(VertexMode vmode, int vertexCount,
SkScalarToFloat(vertices[0].fY));
}
-void SkDumpCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
- const SkPoint* points = patch.getControlPoints();
- const SkColor* color = patch.getColors();
+void SkDumpCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
//dumps corner points and colors in clockwise order starting on upper-left corner
this->dump(kDrawPatch_Verb, &paint, "drawPatch(Vertices{[%f, %f], [%f, %f], [%f, %f], [%f, %f]}\
- | Colors{[0x%x], [0x%x], [0x%x], [0x%x]})",
- points[SkPatch::kTopP0_CubicCtrlPts].fX, points[SkPatch::kTopP0_CubicCtrlPts].fY,
- points[SkPatch::kTopP3_CubicCtrlPts].fX, points[SkPatch::kTopP3_CubicCtrlPts].fY,
- points[SkPatch::kBottomP3_CubicCtrlPts].fX,points[SkPatch::kBottomP3_CubicCtrlPts].fY,
- points[SkPatch::kBottomP0_CubicCtrlPts].fX,points[SkPatch::kBottomP0_CubicCtrlPts].fY,
- color[0], color[1], color[2], color[3]);
+ | Colors{[0x%x], [0x%x], [0x%x], [0x%x]} | TexCoords{[%f,%f], [%f,%f], [%f,%f], \
+ [%f,%f]})",
+ cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fX,
+ cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fY,
+ cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fX,
+ cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fY,
+ cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fX,
+ cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fY,
+ cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fX,
+ cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fY,
+ colors[0], colors[1], colors[2], colors[3],
+ texCoords[0].x(), texCoords[0].y(), texCoords[1].x(), texCoords[1].y(),
+ texCoords[2].x(), texCoords[2].y(), texCoords[3].x(), texCoords[3].y());
}
void SkDumpCanvas::drawData(const void* data, size_t length) {
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index d02835af65..d436bd4a6b 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -285,10 +285,12 @@ void SkNWayCanvas::drawVertices(VertexMode vmode, int vertexCount,
}
}
-void SkNWayCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
Iter iter(fList);
while (iter.next()) {
- iter->drawPatch(patch, paint);
+ iter->drawPatch(cubics, colors, texCoords, xmode, paint);
}
}
diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
index ab15290a34..d12019551d 100644
--- a/src/utils/SkPatchUtils.cpp
+++ b/src/utils/SkPatchUtils.cpp
@@ -7,8 +7,121 @@
#include "SkPatchUtils.h"
+#include "SkColorPriv.h"
+#include "SkGeometry.h"
+
+/**
+ * Evaluator to sample the values of a cubic bezier using forward differences.
+ * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
+ * adding precalculated values.
+ * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
+ * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
+ * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
+ * obtaining this value (mh) we could just add this constant step to our first sampled point
+ * to compute the next one.
+ *
+ * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
+ * apply again forward differences and get linear function to which we can apply again forward
+ * differences to get a constant difference. This is why we keep an array of size 4, the 0th
+ * position keeps the sampled value while the next ones keep the quadratic, linear and constant
+ * difference values.
+ */
+
+class FwDCubicEvaluator {
+
+public:
+ FwDCubicEvaluator()
+ : fMax(0)
+ , fCurrent(0)
+ , fDivisions(0) {
+ memset(fPoints, 0, 4 * sizeof(SkPoint));
+ memset(fPoints, 0, 4 * sizeof(SkPoint));
+ memset(fPoints, 0, 4 * sizeof(SkPoint));
+ }
+
+ /**
+ * Receives the 4 control points of the cubic bezier.
+ */
+ FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
+ fPoints[0] = a;
+ fPoints[1] = b;
+ fPoints[2] = c;
+ fPoints[3] = d;
+
+ SkScalar cx[4], cy[4];
+ SkGetCubicCoeff(fPoints, cx, cy);
+ fCoefs[0].set(cx[0], cy[0]);
+ fCoefs[1].set(cx[1], cy[1]);
+ fCoefs[2].set(cx[2], cy[2]);
+ fCoefs[3].set(cx[3], cy[3]);
+
+ this->restart(1);
+ }
+
+ explicit FwDCubicEvaluator(const SkPoint points[4]) {
+ memcpy(fPoints, points, 4 * sizeof(SkPoint));
+
+ SkScalar cx[4], cy[4];
+ SkGetCubicCoeff(fPoints, cx, cy);
+ fCoefs[0].set(cx[0], cy[0]);
+ fCoefs[1].set(cx[1], cy[1]);
+ fCoefs[2].set(cx[2], cy[2]);
+ fCoefs[3].set(cx[3], cy[3]);
+
+ this->restart(1);
+ }
+
+ /**
+ * Restarts the forward differences evaluator to the first value of t = 0.
+ */
+ void restart(int divisions) {
+ fDivisions = divisions;
+ SkScalar h = 1.f / fDivisions;
+ fCurrent = 0;
+ fMax = fDivisions + 1;
+ fFwDiff[0] = fCoefs[3];
+ SkScalar h2 = h * h;
+ SkScalar h3 = h2 * h;
+
+ fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
+ fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
+ fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
+ fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
+ fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
+ }
+
+ /**
+ * Check if the evaluator is still within the range of 0<=t<=1
+ */
+ bool done() const {
+ return fCurrent > fMax;
+ }
+
+ /**
+ * Call next to obtain the SkPoint sampled and move to the next one.
+ */
+ SkPoint next() {
+ SkPoint point = fFwDiff[0];
+ fFwDiff[0] += fFwDiff[1];
+ fFwDiff[1] += fFwDiff[2];
+ fFwDiff[2] += fFwDiff[3];
+ fCurrent++;
+ return point;
+ }
+
+ const SkPoint* getCtrlPoints() const {
+ return fPoints;
+ }
+
+private:
+ int fMax, fCurrent, fDivisions;
+ SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
// size in pixels of each partition per axis, adjust this knob
-static const int kPartitionSize = 15;
+static const int kPartitionSize = 10;
/**
* Calculate the approximate arc length given a bezier curve's control points.
@@ -24,32 +137,188 @@ static SkScalar approx_arc_length(SkPoint* points, int count) {
return arcLength;
}
-SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix) {
-
- SkPoint mapPts[12];
- matrix->mapPoints(mapPts, patch.getControlPoints(), 12);
+static SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
+ SkScalar c11) {
+ SkScalar a = c00 * (1.f - tx) + c10 * tx;
+ SkScalar b = c01 * (1.f - tx) + c11 * tx;
+ return a * (1.f - ty) + b * ty;
+}
+
+SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) {
// Approximate length of each cubic.
- SkPoint pts[4];
- patch.getTopPoints(pts);
- matrix->mapPoints(pts, 4);
- SkScalar topLength = approx_arc_length(pts, 4);
+ SkPoint pts[kNumPtsCubic];
+ SkPatchUtils::getTopCubic(cubics, pts);
+ matrix->mapPoints(pts, kNumPtsCubic);
+ SkScalar topLength = approx_arc_length(pts, kNumPtsCubic);
- patch.getBottomPoints(pts);
- matrix->mapPoints(pts, 4);
- SkScalar bottomLength = approx_arc_length(pts, 4);
+ SkPatchUtils::getBottomCubic(cubics, pts);
+ matrix->mapPoints(pts, kNumPtsCubic);
+ SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic);
- patch.getLeftPoints(pts);
- matrix->mapPoints(pts, 4);
- SkScalar leftLength = approx_arc_length(pts, 4);
+ SkPatchUtils::getLeftCubic(cubics, pts);
+ matrix->mapPoints(pts, kNumPtsCubic);
+ SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic);
- patch.getRightPoints(pts);
- matrix->mapPoints(pts, 4);
- SkScalar rightLength = approx_arc_length(pts, 4);
+ SkPatchUtils::getRightCubic(cubics, pts);
+ matrix->mapPoints(pts, kNumPtsCubic);
+ SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic);
// Level of detail per axis, based on the larger side between top and bottom or left and right
int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitionSize);
int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitionSize);
- return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY));
+ return SkISize::Make(SkMax32(8, lodX), SkMax32(8, lodY));
+}
+
+void SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) {
+ points[0] = cubics[kTopP0_CubicCtrlPts];
+ points[1] = cubics[kTopP1_CubicCtrlPts];
+ points[2] = cubics[kTopP2_CubicCtrlPts];
+ points[3] = cubics[kTopP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) {
+ points[0] = cubics[kBottomP0_CubicCtrlPts];
+ points[1] = cubics[kBottomP1_CubicCtrlPts];
+ points[2] = cubics[kBottomP2_CubicCtrlPts];
+ points[3] = cubics[kBottomP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) {
+ points[0] = cubics[kLeftP0_CubicCtrlPts];
+ points[1] = cubics[kLeftP1_CubicCtrlPts];
+ points[2] = cubics[kLeftP2_CubicCtrlPts];
+ points[3] = cubics[kLeftP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
+ points[0] = cubics[kRightP0_CubicCtrlPts];
+ points[1] = cubics[kRightP1_CubicCtrlPts];
+ points[2] = cubics[kRightP2_CubicCtrlPts];
+ points[3] = cubics[kRightP3_CubicCtrlPts];
+}
+
+bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
+ const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) {
+ if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) {
+ return false;
+ }
+
+ // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
+ data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
+ lodX = SkMin32(lodX, 255);
+ lodY = SkMin32(lodY, 255);
+ data->fIndexCount = lodX * lodY * 6;
+
+ data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
+ data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
+
+ // if colors is not null then create array for colors
+ SkPMColor colorsPM[kNumCorners];
+ if (NULL != colors) {
+ // premultiply colors to avoid color bleeding.
+ for (int i = 0; i < kNumCorners; i++) {
+ colorsPM[i] = SkPreMultiplyColor(colors[i]);
+ }
+ data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
+ }
+
+ // if texture coordinates are not null then create array for them
+ if (NULL != texCoords) {
+ data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
+ }
+
+ SkPoint pts[kNumPtsCubic];
+ SkPatchUtils::getBottomCubic(cubics, pts);
+ FwDCubicEvaluator fBottom(pts);
+ SkPatchUtils::getTopCubic(cubics, pts);
+ FwDCubicEvaluator fTop(pts);
+ SkPatchUtils::getLeftCubic(cubics, pts);
+ FwDCubicEvaluator fLeft(pts);
+ SkPatchUtils::getRightCubic(cubics, pts);
+ FwDCubicEvaluator fRight(pts);
+
+ fBottom.restart(lodX);
+ fTop.restart(lodX);
+
+ SkScalar u = 0.0f;
+ int stride = lodY + 1;
+ for (int x = 0; x <= lodX; x++) {
+ SkPoint bottom = fBottom.next(), top = fTop.next();
+ fLeft.restart(lodY);
+ fRight.restart(lodY);
+ SkScalar v = 0.f;
+ for (int y = 0; y <= lodY; y++) {
+ int dataIndex = x * (lodY + 1) + y;
+
+ SkPoint left = fLeft.next(), right = fRight.next();
+
+ SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
+ (1.0f - v) * top.y() + v * bottom.y());
+ SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
+ (1.0f - u) * left.y() + u * right.y());
+ SkPoint s2 = SkPoint::Make(
+ (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
+ + u * fTop.getCtrlPoints()[3].x())
+ + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
+ + u * fBottom.getCtrlPoints()[3].x()),
+ (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
+ + u * fTop.getCtrlPoints()[3].y())
+ + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
+ + u * fBottom.getCtrlPoints()[3].y()));
+ data->fPoints[dataIndex] = s0 + s1 - s2;
+
+ if (NULL != colors) {
+ uint8_t a = uint8_t(bilerp(u, v,
+ SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])),
+ SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])),
+ SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])),
+ SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner]))));
+ uint8_t r = uint8_t(bilerp(u, v,
+ SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])),
+ SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])),
+ SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])),
+ SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner]))));
+ uint8_t g = uint8_t(bilerp(u, v,
+ SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])),
+ SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])),
+ SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])),
+ SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner]))));
+ uint8_t b = uint8_t(bilerp(u, v,
+ SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])),
+ SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])),
+ SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])),
+ SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner]))));
+ data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
+ }
+
+ if (NULL != texCoords) {
+ data->fTexCoords[dataIndex] = SkPoint::Make(
+ bilerp(u, v, texCoords[kTopLeft_Corner].x(),
+ texCoords[kTopRight_Corner].x(),
+ texCoords[kBottomLeft_Corner].x(),
+ texCoords[kBottomRight_Corner].x()),
+ bilerp(u, v, texCoords[kTopLeft_Corner].y(),
+ texCoords[kTopRight_Corner].y(),
+ texCoords[kBottomLeft_Corner].y(),
+ texCoords[kBottomRight_Corner].y()));
+
+ }
+
+ if(x < lodX && y < lodY) {
+ int i = 6 * (x * lodY + y);
+ data->fIndices[i] = x * stride + y;
+ data->fIndices[i + 1] = x * stride + 1 + y;
+ data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
+ data->fIndices[i + 3] = data->fIndices[i];
+ data->fIndices[i + 4] = data->fIndices[i + 2];
+ data->fIndices[i + 5] = (x + 1) * stride + y;
+ }
+ v = SkScalarClampMax(v + 1.f / lodY, 1);
+ }
+ u = SkScalarClampMax(u + 1.f / lodX, 1);
+ }
+ return true;
+
}
diff --git a/src/utils/SkPatchUtils.h b/src/utils/SkPatchUtils.h
index f2e3b43ed1..879053ad0c 100644
--- a/src/utils/SkPatchUtils.h
+++ b/src/utils/SkPatchUtils.h
@@ -8,16 +8,114 @@
#ifndef SkPatchUtils_DEFINED
#define SkPatchUtils_DEFINED
-#include "SkPatch.h"
+#include "SkColorPriv.h"
#include "SkMatrix.h"
class SK_API SkPatchUtils {
-
+
public:
/**
+ * Structure that holds the vertex data related to the tessellation of a patch. It is passed
+ * as a parameter to the function getVertexData which sets the points, colors and texture
+ * coordinates of the vertices and the indices for them to be drawn as triangles.
+ */
+ struct VertexData {
+ int fVertexCount, fIndexCount;
+ SkPoint* fPoints;
+ SkPoint* fTexCoords;
+ uint32_t* fColors;
+ uint16_t* fIndices;
+
+ VertexData()
+ : fVertexCount(0)
+ , fIndexCount(0)
+ , fPoints(NULL)
+ , fTexCoords(NULL)
+ , fColors(NULL)
+ , fIndices(NULL) { }
+
+ ~VertexData() {
+ SkDELETE_ARRAY(fPoints);
+ SkDELETE_ARRAY(fTexCoords);
+ SkDELETE_ARRAY(fColors);
+ SkDELETE_ARRAY(fIndices);
+ }
+ };
+
+ // Enums for control points based on the order specified in the constructor (clockwise).
+ enum CubicCtrlPts {
+ kTopP0_CubicCtrlPts = 0,
+ kTopP1_CubicCtrlPts = 1,
+ kTopP2_CubicCtrlPts = 2,
+ kTopP3_CubicCtrlPts = 3,
+
+ kRightP0_CubicCtrlPts = 3,
+ kRightP1_CubicCtrlPts = 4,
+ kRightP2_CubicCtrlPts = 5,
+ kRightP3_CubicCtrlPts = 6,
+
+ kBottomP0_CubicCtrlPts = 9,
+ kBottomP1_CubicCtrlPts = 8,
+ kBottomP2_CubicCtrlPts = 7,
+ kBottomP3_CubicCtrlPts = 6,
+
+ kLeftP0_CubicCtrlPts = 0,
+ kLeftP1_CubicCtrlPts = 11,
+ kLeftP2_CubicCtrlPts = 10,
+ kLeftP3_CubicCtrlPts = 9,
+ };
+
+ // Enum for corner also clockwise.
+ enum Corner {
+ kTopLeft_Corner = 0,
+ kTopRight_Corner,
+ kBottomRight_Corner,
+ kBottomLeft_Corner
+ };
+
+ enum {
+ kNumCtrlPts = 12,
+ kNumCorners = 4,
+ kNumPtsCubic = 4
+ };
+
+ /**
* Method that calculates a level of detail (number of subdivisions) for a patch in both axis.
*/
- static SkISize GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix);
+ static SkISize GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix);
+
+ /**
+ * Get the points corresponding to the top cubic of cubics.
+ */
+ static void getTopCubic(const SkPoint cubics[12], SkPoint points[4]);
+
+ /**
+ * Get the points corresponding to the bottom cubic of cubics.
+ */
+ static void getBottomCubic(const SkPoint cubics[12], SkPoint points[4]);
+
+ /**
+ * Get the points corresponding to the left cubic of cubics.
+ */
+ static void getLeftCubic(const SkPoint cubics[12], SkPoint points[4]);
+
+ /**
+ * Get the points corresponding to the right cubic of cubics.
+ */
+ static void getRightCubic(const SkPoint cubics[12], SkPoint points[4]);
+
+ /**
+ * Function that evaluates the coons patch interpolation.
+ * data refers to the pointer of the PatchData struct in which the tessellation data is set.
+ * cubics refers to the points of the cubics.
+ * lod refers the level of detail for each axis.
+ * colors refers to the corner colors that will be bilerp across the patch (optional parameter)
+ * texCoords refers to the corner texture coordinates that will be bilerp across the patch
+ (optional parameter)
+ */
+ static bool getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
+ const SkColor colors[4], const SkPoint texCoords[4],
+ int lodX, int lodY);
};
#endif
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 773fd201ab..c15acaa78f 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -150,8 +150,10 @@ void SkProxyCanvas::drawVertices(VertexMode vmode, int vertexCount,
xmode, indices, indexCount, paint);
}
-void SkProxyCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
- fProxy->drawPatch(patch, paint);
+void SkProxyCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
+ fProxy->drawPatch(cubics, colors, texCoords, xmode, paint);
}
void SkProxyCanvas::drawData(const void* data, size_t length) {