Index: src/utils/android/SkAndroidSDKFilterCanvas.cpp |
diff --git a/src/utils/android/SkAndroidSDKFilterCanvas.cpp b/src/utils/android/SkAndroidSDKFilterCanvas.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4157a616bb8adc8b80dcfd269347015ed60c361a |
--- /dev/null |
+++ b/src/utils/android/SkAndroidSDKFilterCanvas.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 "SkAndroidSDKFilterCanvas.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); \ |
+ } |
+ |
+ |
+SkAndroidSDKFilterCanvas::SkAndroidSDKFilterCanvas() : fProxyTarget(NULL) { } |
+ |
+void SkAndroidSDKFilterCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; } |
+ |
+void SkAndroidSDKFilterCanvas::onDrawPaint(const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawPaint(filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawPoints(PointMode pMode, |
+ size_t count, |
+ const SkPoint pts[], |
+ const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawPoints(pMode, count, pts, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawOval(r, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawRect(r, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawRRect(r, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawPath(path, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawBitmap(const SkBitmap& bitmap, |
+ SkScalar left, |
+ SkScalar top, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::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 SkAndroidSDKFilterCanvas::onDrawBitmapNine(const SkBitmap& bitmap, |
+ const SkIRect& center, |
+ const SkRect& dst, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawSprite(const SkBitmap& bitmap, |
+ int left, |
+ int top, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawSprite(bitmap, left, top, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::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 SkAndroidSDKFilterCanvas::onDrawDRRect(const SkRRect& outer, |
+ const SkRRect& inner, |
+ const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawDRRect(outer, inner, filteredPaint); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onDrawText(const void* text, |
+ size_t byteLength, |
+ SkScalar x, |
+ SkScalar y, |
+ const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawText(text, byteLength, x, y, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::onDrawPosText(const void* text, |
+ size_t byteLength, |
+ const SkPoint pos[], |
+ const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint); |
+} |
+void SkAndroidSDKFilterCanvas::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 SkAndroidSDKFilterCanvas::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 SkAndroidSDKFilterCanvas::onDrawTextBlob(const SkTextBlob* blob, |
+ SkScalar x, |
+ SkScalar y, |
+ const SkPaint& paint) { |
+ FILTER(paint); |
+ fProxyTarget->drawTextBlob(blob, x, y, filteredPaint); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::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 SkAndroidSDKFilterCanvas::onDrawImage(const SkImage* image, |
+ SkScalar x, |
+ SkScalar y, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawImage(image, x, y, filteredPaint); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onDrawImageRect(const SkImage* image, |
+ const SkRect* in, |
+ const SkRect& out, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawImageRect(image, in, out, filteredPaint); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onDrawPicture(const SkPicture* picture, |
+ const SkMatrix* matrix, |
+ const SkPaint* paint) { |
+ FILTER_PTR(paint); |
+ fProxyTarget->drawPicture(picture, matrix, filteredPaint); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onDrawDrawable(SkDrawable* drawable) { |
+ fProxyTarget->drawDrawable(drawable); |
+} |
+ |
+SkISize SkAndroidSDKFilterCanvas::getBaseLayerSize() const { |
+ return fProxyTarget->getBaseLayerSize(); |
+} |
+bool SkAndroidSDKFilterCanvas::getClipBounds(SkRect* rect) const { |
+ return fProxyTarget->getClipBounds(rect); |
+} |
+bool SkAndroidSDKFilterCanvas::getClipDeviceBounds(SkIRect* rect) const { |
+ return fProxyTarget->getClipDeviceBounds(rect); |
+} |
+ |
+bool SkAndroidSDKFilterCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); } |
+bool SkAndroidSDKFilterCanvas::isClipRect() const { return fProxyTarget->isClipRect(); } |
+ |
+SkSurface* SkAndroidSDKFilterCanvas::onNewSurface(const SkImageInfo& info, |
+ const SkSurfaceProps& props) { |
+ return fProxyTarget->newSurface(info, &props); |
+} |
+ |
+const void* SkAndroidSDKFilterCanvas::onPeekPixels(SkImageInfo* info, size_t* data) { |
+ return fProxyTarget->peekPixels(info, data); |
+} |
+ |
+void* SkAndroidSDKFilterCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* data) { |
+ return fProxyTarget->accessTopLayerPixels(info, data); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::willSave() { fProxyTarget->save(); } |
+void SkAndroidSDKFilterCanvas::willRestore() { fProxyTarget->restore(); } |
+void SkAndroidSDKFilterCanvas::didRestore() { } |
+void SkAndroidSDKFilterCanvas::didConcat(const SkMatrix& m) { |
+ fProxyTarget->concat(m); |
+} |
+void SkAndroidSDKFilterCanvas::didSetMatrix(const SkMatrix& m) { fProxyTarget->setMatrix(m); } |
+ |
+void SkAndroidSDKFilterCanvas::onClipRect(const SkRect& rect, |
+ SkRegion::Op op, |
+ ClipEdgeStyle style) { |
+ fProxyTarget->clipRect(rect, op, style); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onClipRRect(const SkRRect& rrect, |
+ SkRegion::Op op, |
+ ClipEdgeStyle style) { |
+ fProxyTarget->clipRRect(rrect, op, style); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onClipPath(const SkPath& path, |
+ SkRegion::Op op, |
+ ClipEdgeStyle style) { |
+ fProxyTarget->clipPath(path, op, style); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) { |
+ fProxyTarget->clipRegion(region, op); |
+} |
+ |
+void SkAndroidSDKFilterCanvas::onDiscard() { fProxyTarget->discard(); } |
+ |
+ |