summaryrefslogtreecommitdiffstats
path: root/chromium/skia/ext/pixel_ref_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/skia/ext/pixel_ref_utils.cc')
-rw-r--r--chromium/skia/ext/pixel_ref_utils.cc375
1 files changed, 375 insertions, 0 deletions
diff --git a/chromium/skia/ext/pixel_ref_utils.cc b/chromium/skia/ext/pixel_ref_utils.cc
new file mode 100644
index 00000000000..85a4e4896ab
--- /dev/null
+++ b/chromium/skia/ext/pixel_ref_utils.cc
@@ -0,0 +1,375 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "skia/ext/pixel_ref_utils.h"
+
+#include <algorithm>
+
+#include "third_party/skia/include/core/SkBitmapDevice.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "third_party/skia/include/core/SkDraw.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
+#include "third_party/skia/include/core/SkRRect.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkShader.h"
+#include "third_party/skia/include/utils/SkNoSaveLayerCanvas.h"
+#include "third_party/skia/src/core/SkRasterClip.h"
+
+namespace skia {
+
+namespace {
+
+// URI label for a discardable SkPixelRef.
+const char kLabelDiscardable[] = "discardable";
+
+class DiscardablePixelRefSet {
+ public:
+ DiscardablePixelRefSet(
+ std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs)
+ : pixel_refs_(pixel_refs) {}
+
+ void Add(SkPixelRef* pixel_ref, const SkRect& rect) {
+ // Only save discardable pixel refs.
+ if (pixel_ref->getURI() &&
+ !strcmp(pixel_ref->getURI(), kLabelDiscardable)) {
+ PixelRefUtils::PositionPixelRef position_pixel_ref;
+ position_pixel_ref.pixel_ref = pixel_ref;
+ position_pixel_ref.pixel_ref_rect = rect;
+ pixel_refs_->push_back(position_pixel_ref);
+ }
+ }
+
+ private:
+ std::vector<PixelRefUtils::PositionPixelRef>* pixel_refs_;
+};
+
+class GatherPixelRefDevice : public SkBitmapDevice {
+ public:
+ GatherPixelRefDevice(const SkBitmap& bm,
+ DiscardablePixelRefSet* pixel_ref_set)
+ : SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
+
+ virtual void clear(SkColor color) SK_OVERRIDE {}
+ virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (GetBitmapFromPaint(paint, &bitmap)) {
+ SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
+ AddBitmap(bitmap, clip_rect);
+ }
+ }
+
+ virtual void drawPoints(const SkDraw& draw,
+ SkCanvas::PointMode mode,
+ size_t count,
+ const SkPoint points[],
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (!GetBitmapFromPaint(paint, &bitmap))
+ return;
+
+ if (count == 0)
+ return;
+
+ SkPoint min_point = points[0];
+ SkPoint max_point = points[0];
+ for (size_t i = 1; i < count; ++i) {
+ const SkPoint& point = points[i];
+ min_point.set(std::min(min_point.x(), point.x()),
+ std::min(min_point.y(), point.y()));
+ max_point.set(std::max(max_point.x(), point.x()),
+ std::max(max_point.y(), point.y()));
+ }
+
+ SkRect bounds = SkRect::MakeLTRB(
+ min_point.x(), min_point.y(), max_point.x(), max_point.y());
+
+ GatherPixelRefDevice::drawRect(draw, bounds, paint);
+ }
+ virtual void drawRect(const SkDraw& draw,
+ const SkRect& rect,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (GetBitmapFromPaint(paint, &bitmap)) {
+ SkRect mapped_rect;
+ draw.fMatrix->mapRect(&mapped_rect, rect);
+ mapped_rect.intersect(SkRect::Make(draw.fRC->getBounds()));
+ AddBitmap(bitmap, mapped_rect);
+ }
+ }
+ virtual void drawOval(const SkDraw& draw,
+ const SkRect& rect,
+ const SkPaint& paint) SK_OVERRIDE {
+ GatherPixelRefDevice::drawRect(draw, rect, paint);
+ }
+ virtual void drawRRect(const SkDraw& draw,
+ const SkRRect& rect,
+ const SkPaint& paint) SK_OVERRIDE {
+ GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
+ }
+ virtual void drawPath(const SkDraw& draw,
+ const SkPath& path,
+ const SkPaint& paint,
+ const SkMatrix* pre_path_matrix,
+ bool path_is_mutable) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (!GetBitmapFromPaint(paint, &bitmap))
+ return;
+
+ SkRect path_bounds = path.getBounds();
+ SkRect final_rect;
+ if (pre_path_matrix != NULL)
+ pre_path_matrix->mapRect(&final_rect, path_bounds);
+ else
+ final_rect = path_bounds;
+
+ GatherPixelRefDevice::drawRect(draw, final_rect, paint);
+ }
+ virtual void drawBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkMatrix& matrix,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkMatrix total_matrix;
+ total_matrix.setConcat(*draw.fMatrix, matrix);
+
+ SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
+ SkRect mapped_rect;
+ total_matrix.mapRect(&mapped_rect, bitmap_rect);
+ AddBitmap(bitmap, mapped_rect);
+
+ SkBitmap paint_bitmap;
+ if (GetBitmapFromPaint(paint, &paint_bitmap))
+ AddBitmap(paint_bitmap, mapped_rect);
+ }
+ virtual void drawBitmapRect(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkRect* src_or_null,
+ const SkRect& dst,
+ const SkPaint& paint,
+ SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
+ SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
+ SkMatrix matrix;
+ matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
+ GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
+ }
+ virtual void drawSprite(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ int x,
+ int y,
+ const SkPaint& paint) SK_OVERRIDE {
+ // Sprites aren't affected by current matrix, so we can't reuse drawRect.
+ SkMatrix matrix;
+ matrix.setTranslate(x, y);
+
+ SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
+ SkRect mapped_rect;
+ matrix.mapRect(&mapped_rect, bitmap_rect);
+
+ AddBitmap(bitmap, mapped_rect);
+ SkBitmap paint_bitmap;
+ if (GetBitmapFromPaint(paint, &paint_bitmap))
+ AddBitmap(paint_bitmap, mapped_rect);
+ }
+ virtual void drawText(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (!GetBitmapFromPaint(paint, &bitmap))
+ return;
+
+ // Math is borrowed from SkBBoxRecord
+ SkRect bounds;
+ paint.measureText(text, len, &bounds);
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+
+ if (paint.isVerticalText()) {
+ SkScalar h = bounds.fBottom - bounds.fTop;
+ if (paint.getTextAlign() == SkPaint::kCenter_Align) {
+ bounds.fTop -= h / 2;
+ bounds.fBottom -= h / 2;
+ }
+ bounds.fBottom += metrics.fBottom;
+ bounds.fTop += metrics.fTop;
+ } else {
+ SkScalar w = bounds.fRight - bounds.fLeft;
+ if (paint.getTextAlign() == SkPaint::kCenter_Align) {
+ bounds.fLeft -= w / 2;
+ bounds.fRight -= w / 2;
+ } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
+ bounds.fLeft -= w;
+ bounds.fRight -= w;
+ }
+ bounds.fTop = metrics.fTop;
+ bounds.fBottom = metrics.fBottom;
+ }
+
+ SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
+ bounds.fLeft -= pad;
+ bounds.fRight += pad;
+ bounds.fLeft += x;
+ bounds.fRight += x;
+ bounds.fTop += y;
+ bounds.fBottom += y;
+
+ GatherPixelRefDevice::drawRect(draw, bounds, paint);
+ }
+ virtual void drawPosText(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkScalar pos[],
+ SkScalar const_y,
+ int scalars_per_pos,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (!GetBitmapFromPaint(paint, &bitmap))
+ return;
+
+ if (len == 0)
+ return;
+
+ // Similar to SkDraw asserts.
+ SkASSERT(scalars_per_pos == 1 || scalars_per_pos == 2);
+
+ SkPoint min_point;
+ SkPoint max_point;
+ if (scalars_per_pos == 1) {
+ min_point.set(pos[0], const_y);
+ max_point.set(pos[0], const_y);
+ } else if (scalars_per_pos == 2) {
+ min_point.set(pos[0], const_y + pos[1]);
+ max_point.set(pos[0], const_y + pos[1]);
+ }
+
+ for (size_t i = 0; i < len; ++i) {
+ SkScalar x = pos[i * scalars_per_pos];
+ SkScalar y = const_y;
+ if (scalars_per_pos == 2)
+ y += pos[i * scalars_per_pos + 1];
+
+ min_point.set(std::min(x, min_point.x()), std::min(y, min_point.y()));
+ max_point.set(std::max(x, max_point.x()), std::max(y, max_point.y()));
+ }
+
+ SkRect bounds = SkRect::MakeLTRB(
+ min_point.x(), min_point.y(), max_point.x(), max_point.y());
+
+ // Math is borrowed from SkBBoxRecord
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+
+ bounds.fTop += metrics.fTop;
+ bounds.fBottom += metrics.fBottom;
+
+ SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
+ bounds.fLeft += pad;
+ bounds.fRight -= pad;
+
+ GatherPixelRefDevice::drawRect(draw, bounds, paint);
+ }
+ virtual void drawTextOnPath(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint& paint) SK_OVERRIDE {
+ SkBitmap bitmap;
+ if (!GetBitmapFromPaint(paint, &bitmap))
+ return;
+
+ // Math is borrowed from SkBBoxRecord
+ SkRect bounds = path.getBounds();
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+
+ SkScalar pad = metrics.fTop;
+ bounds.fLeft += pad;
+ bounds.fRight -= pad;
+ bounds.fTop += pad;
+ bounds.fBottom -= pad;
+
+ GatherPixelRefDevice::drawRect(draw, bounds, paint);
+ }
+ virtual void drawVertices(const SkDraw& draw,
+ SkCanvas::VertexMode,
+ int vertex_count,
+ const SkPoint verts[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ SkXfermode* xmode,
+ const uint16_t indices[],
+ int index_count,
+ const SkPaint& paint) SK_OVERRIDE {
+ GatherPixelRefDevice::drawPoints(
+ draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
+ }
+ virtual void drawDevice(const SkDraw&,
+ SkBaseDevice*,
+ int x,
+ int y,
+ const SkPaint&) SK_OVERRIDE {}
+
+ protected:
+ virtual bool onReadPixels(const SkImageInfo& info,
+ void* pixels,
+ size_t rowBytes,
+ int x,
+ int y) SK_OVERRIDE {
+ return false;
+ }
+
+ virtual bool onWritePixels(const SkImageInfo& info,
+ const void* pixels,
+ size_t rowBytes,
+ int x,
+ int y) SK_OVERRIDE {
+ return false;
+ }
+
+ private:
+ DiscardablePixelRefSet* pixel_ref_set_;
+
+ void AddBitmap(const SkBitmap& bm, const SkRect& rect) {
+ SkRect canvas_rect = SkRect::MakeWH(width(), height());
+ SkRect paint_rect = SkRect::MakeEmpty();
+ paint_rect.intersect(rect, canvas_rect);
+ pixel_ref_set_->Add(bm.pixelRef(), paint_rect);
+ }
+
+ bool GetBitmapFromPaint(const SkPaint& paint, SkBitmap* bm) {
+ SkShader* shader = paint.getShader();
+ if (shader) {
+ // Check whether the shader is a gradient in order to prevent generation
+ // of bitmaps from gradient shaders, which implement asABitmap.
+ if (SkShader::kNone_GradientType == shader->asAGradient(NULL))
+ return shader->asABitmap(bm, NULL, NULL);
+ }
+ return false;
+ }
+};
+
+} // namespace
+
+void PixelRefUtils::GatherDiscardablePixelRefs(
+ SkPicture* picture,
+ std::vector<PositionPixelRef>* pixel_refs) {
+ pixel_refs->clear();
+ DiscardablePixelRefSet pixel_ref_set(pixel_refs);
+
+ SkBitmap empty_bitmap;
+ empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
+
+ GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
+ SkNoSaveLayerCanvas canvas(&device);
+
+ canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
+ SkRegion::kIntersect_Op,
+ false);
+ canvas.drawPicture(picture);
+}
+
+} // namespace skia