Both DM and nanobench need this, so moving the duplicated code to
one common spot. (It's incomplete, and has had bugs, so it's not
like we can confidently write once, copy-paste, and not maintain
again.)
Because SkPathEffect::exposedInAndroidJavaAPI() only builds in the
Android Framework, we might want to make all this code Framework-only?
R=djsollen@google.com,mtklein@google.com
Review URL: https://codereview.chromium.org/1021823003
diff --git a/src/utils/android/SkAndroidSDKCanvas.cpp b/src/utils/android/SkAndroidSDKCanvas.cpp
new file mode 100644
index 0000000..d02fd72
--- /dev/null
+++ b/src/utils/android/SkAndroidSDKCanvas.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAndroidSDKCanvas.h"
+
+#include "SkColorFilter.h"
+#include "SkPathEffect.h"
+#include "SkShader.h"
+
+namespace {
+
+/** Discard SkShaders not exposed by the Android Java API. */
+
+void CheckShader(SkPaint* paint) {
+ SkShader* shader = paint->getShader();
+ if (!shader) {
+ return;
+ }
+
+ if (shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+ return;
+ }
+ if (shader->asACompose(NULL)) {
+ return;
+ }
+ SkShader::GradientType gtype = shader->asAGradient(NULL);
+ if (gtype == SkShader::kLinear_GradientType ||
+ gtype == SkShader::kRadial_GradientType ||
+ gtype == SkShader::kSweep_GradientType) {
+ return;
+ }
+ paint->setShader(NULL);
+}
+
+void Filter(SkPaint* paint) {
+
+ uint32_t flags = paint->getFlags();
+ flags &= ~SkPaint::kLCDRenderText_Flag;
+ paint->setFlags(flags);
+
+ // Android doesn't support Xfermodes above kLighten_Mode
+ SkXfermode::Mode mode;
+ SkXfermode::AsMode(paint->getXfermode(), &mode);
+ if (mode > SkXfermode::kLighten_Mode) {
+ paint->setXfermode(NULL);
+ }
+
+ // Force bilinear scaling or none
+ if (paint->getFilterQuality() != kNone_SkFilterQuality) {
+ paint->setFilterQuality(kLow_SkFilterQuality);
+ }
+
+ CheckShader(paint);
+
+ // Android SDK only supports mode & matrix color filters
+ // (and, again, no modes above kLighten_Mode).
+ SkColorFilter* cf = paint->getColorFilter();
+ if (cf) {
+ SkColor color;
+ SkXfermode::Mode mode;
+ SkScalar srcColorMatrix[20];
+ bool isMode = cf->asColorMode(&color, &mode);
+ if (isMode && mode > SkXfermode::kLighten_Mode) {
+ paint->setColorFilter(
+ SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcOver_Mode));
+ } else if (!isMode && !cf->asColorMatrix(srcColorMatrix)) {
+ paint->setColorFilter(NULL);
+ }
+ }
+
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+ SkPathEffect* pe = paint->getPathEffect();
+ if (pe && !pe->exposedInAndroidJavaAPI()) {
+ paint->setPathEffect(NULL);
+ }
+#endif
+
+ // TODO: Android doesn't support all the flags that can be passed to
+ // blur filters; we need plumbing to get them out.
+
+ paint->setImageFilter(NULL);
+ paint->setLooper(NULL);
+};
+
+} // namespace
+
+#define FILTER(p) \
+ SkPaint filteredPaint(p); \
+ Filter(&filteredPaint);
+
+#define FILTER_PTR(p) \
+ SkTLazy<SkPaint> lazyPaint; \
+ SkPaint* filteredPaint = (SkPaint*) p; \
+ if (p) { \
+ filteredPaint = lazyPaint.set(*p); \
+ Filter(filteredPaint); \
+ }
+
+
+SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(NULL) { }
+
+void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; }
+
+void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPaint(filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawPoints(PointMode pMode,
+ size_t count,
+ const SkPoint pts[],
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPoints(pMode, count, pts, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawOval(r, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawRect(r, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawRRect(r, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPath(path, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawBitmap(const SkBitmap& bitmap,
+ SkScalar left,
+ SkScalar top,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawBitmapRect(const SkBitmap& bitmap,
+ const SkRect* src,
+ const SkRect& dst,
+ const SkPaint* paint,
+ DrawBitmapRectFlags flags) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawBitmapRectToRect(bitmap, src, dst, filteredPaint, flags);
+}
+void SkAndroidSDKCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
+ const SkIRect& center,
+ const SkRect& dst,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawSprite(const SkBitmap& bitmap,
+ int left,
+ int top,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawSprite(bitmap, left, top, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawVertices(VertexMode vMode,
+ int vertexCount,
+ const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[], SkXfermode* xMode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawVertices(vMode, vertexCount, vertices, texs, colors,
+ xMode, indices, indexCount, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawDRRect(const SkRRect& outer,
+ const SkRRect& inner,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawDRRect(outer, inner, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawText(const void* text,
+ size_t byteLength,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawText(text, byteLength, x, y, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawPosText(const void* text,
+ size_t byteLength,
+ const SkPoint pos[],
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawPosTextH(const void* text,
+ size_t byteLength,
+ const SkScalar xpos[],
+ SkScalar constY,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text,
+ size_t byteLength,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint);
+}
+void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawTextBlob(blob, x, y, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawPatch(const SkPoint cubics[12],
+ const SkColor colors[4],
+ const SkPoint texCoords[4],
+ SkXfermode* xmode,
+ const SkPaint& paint) {
+ FILTER(paint);
+ fProxyTarget->drawPatch(cubics, colors, texCoords, xmode, filteredPaint);
+}
+
+
+void SkAndroidSDKCanvas::onDrawImage(const SkImage* image,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawImage(image, x, y, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawImageRect(const SkImage* image,
+ const SkRect* in,
+ const SkRect& out,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawImageRect(image, in, out, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) {
+ FILTER_PTR(paint);
+ fProxyTarget->drawPicture(picture, matrix, filteredPaint);
+}
+
+void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable) {
+ fProxyTarget->drawDrawable(drawable);
+}
+
+SkISize SkAndroidSDKCanvas::getBaseLayerSize() const {
+ return fProxyTarget->getBaseLayerSize();
+}
+bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const {
+ return fProxyTarget->getClipBounds(rect);
+}
+bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const {
+ return fProxyTarget->getClipDeviceBounds(rect);
+}
+
+bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); }
+bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); }
+
+SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info,
+ const SkSurfaceProps& props) {
+ return fProxyTarget->newSurface(info, &props);
+}
+
+const void* SkAndroidSDKCanvas::onPeekPixels(SkImageInfo* info, size_t* data) {
+ return fProxyTarget->peekPixels(info, data);
+}
+
+void* SkAndroidSDKCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* data) {
+ return fProxyTarget->accessTopLayerPixels(info, data);
+}
+
+void SkAndroidSDKCanvas::willSave() { fProxyTarget->save(); }
+void SkAndroidSDKCanvas::willRestore() { fProxyTarget->restore(); }
+void SkAndroidSDKCanvas::didRestore() { }
+void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) {
+ fProxyTarget->concat(m);
+}
+void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) { fProxyTarget->setMatrix(m); }
+
+void SkAndroidSDKCanvas::onClipRect(const SkRect& rect,
+ SkRegion::Op op,
+ ClipEdgeStyle style) {
+ fProxyTarget->clipRect(rect, op, style);
+}
+
+void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect,
+ SkRegion::Op op,
+ ClipEdgeStyle style) {
+ fProxyTarget->clipRRect(rrect, op, style);
+}
+
+void SkAndroidSDKCanvas::onClipPath(const SkPath& path,
+ SkRegion::Op op,
+ ClipEdgeStyle style) {
+ fProxyTarget->clipPath(path, op, style);
+}
+
+void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+ fProxyTarget->clipRegion(region, op);
+}
+
+void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); }
+
+