/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGatherPixelRefsAndRects_DEFINED
#define SkGatherPixelRefsAndRects_DEFINED
#include "SkBitmap.h"
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkPictureUtils.h"
#include "SkRasterClip.h"
#include "SkRefCnt.h"
#include "SkRRect.h"
#include "SkTypes.h"
// This GatherPixelRefs device passes all discovered pixel refs and their
// device bounds to the user provided SkPixelRefContainer-derived object
class SkGatherPixelRefsAndRectsDevice : public SkBaseDevice {
public:
SK_DECLARE_INST_COUNT(SkGatherPixelRefsAndRectsDevice)
SkGatherPixelRefsAndRectsDevice(int width, int height,
SkPictureUtils::SkPixelRefContainer* prCont) {
fSize.set(width, height);
fPRCont = prCont;
SkSafeRef(fPRCont);
fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
}
virtual ~SkGatherPixelRefsAndRectsDevice() {
SkSafeUnref(fPRCont);
}
virtual SkImageInfo imageInfo() const SK_OVERRIDE {
return fEmptyBitmap.info();
}
virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
protected:
virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
return false;
}
virtual void clear(SkColor color) SK_OVERRIDE {
NothingToDo();
}
virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
SkBitmap bm;
if (GetBitmapFromPaint(paint, &bm)) {
SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
fPRCont->add(bm.pixelRef(), clipRect);
}
}
virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
SkBitmap bm;
if (!GetBitmapFromPaint(paint, &bm)) {
return;
}
if (0 == count) {
return;
}
SkPoint min = points[0];
SkPoint max = points[0];
for (size_t i = 1; i < count; ++i) {
const SkPoint& point = points[i];
min.set(SkMinScalar(min.x(), point.x()), SkMinScalar(min.y(), point.y()));
max.set(SkMaxScalar(max.x(), point.x()), SkMaxScalar(max.y(), point.y()));
}
SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x()+1, max.y()+1);
this->drawRect(draw, bounds, paint);
}
virtual void drawRect(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) SK_OVERRIDE {
SkBitmap bm;
if (GetBitmapFromPaint(paint, &bm)) {
SkRect mappedRect;
draw.fMatrix->mapRect(&mappedRect, rect);
SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
mappedRect.intersect(clipRect);
fPRCont->add(bm.pixelRef(), mappedRect);
}
}
virtual void drawOval(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) SK_OVERRIDE {
this->drawRect(draw, rect, paint);
}
virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
const SkPaint& paint) SK_OVERRIDE {
this->drawRect(draw, rrect.rect(), paint);
}
virtual void drawPath(const SkDraw& draw, const SkPath& path,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) SK_OVERRIDE {
SkBitmap bm;
if (!GetBitmapFromPaint(paint, &bm)) {
return;
}
SkRect pathBounds = path.getBounds();
if (NULL != prePathMatrix) {
prePathMatrix->mapRect(&pathBounds);
}
this->drawRect(draw, pathBounds, paint);
}
virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
SkMatrix totMatrix;
totMatrix.setConcat(*draw.fMatrix, matrix);
SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
SkIntToScalar(bitmap.height()));
SkRect mappedRect;
totMatrix.mapRect(&mappedRect, bitmapRect);
fPRCont->add(bitmap.pixelRef(), mappedRect);
SkBitmap paintBitmap;
if (GetBitmapFromPaint(paint, &paintBitmap)) {
fPRCont->add(paintBitmap.pixelRef(), mappedRect);
}
}
virtual void drawSprite(const SkDraw&, 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(SkIntToScalar(x), SkIntToScalar(y));
SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
SkIntToScalar(bitmap.height()));
SkRect mappedRect;
matrix.mapRect(&mappedRect, bitmapRect);
fPRCont->add(bitmap.pixelRef(), mappedRect);
SkBitmap paintBitmap;
if (GetBitmapFromPaint(paint, &paintBitmap)) {
fPRCont->add(paintBitmap.pixelRef(), mappedRect);
}
}
virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
const SkRect* srcOrNull, const SkRect& dst,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
SkRect bitmapRect = SkRect::MakeWH(SkIntToScalar(bitmap.width()),
SkIntToScalar(bitmap.height()));
SkMatrix matrix;
matrix.setRectToRect(bitmapRect, dst, SkMatrix::kFill_ScaleToFit);
this->drawBitmap(draw, bitmap, matrix, paint);
}
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.offset(x, y);
this->drawRect(draw, bounds, paint);
}
virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap)) {
return;
}
if (0 == len) {
return;
}
// Similar to SkDraw asserts.
SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
SkScalar y = scalarsPerPos == 1 ? constY : constY + pos[1];
SkPoint min, max;
min.set(pos[0], y);
max.set(pos[0], y);
for (size_t i = 1; i < len; ++i) {
SkScalar x = pos[i * scalarsPerPos];
SkScalar y = constY;
if (2 == scalarsPerPos) {
y += pos[i * scalarsPerPos + 1];
}
min.set(SkMinScalar(x, min.x()), SkMinScalar(y, min.y()));
max.set(SkMaxScalar(x, max.x()), SkMaxScalar(y, max.y()));
}
SkRect bounds = SkRect::MakeLTRB(min.x(), min.y(), max.x(), max.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;
this->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;
// TODO: inset?!
bounds.fLeft += pad;
bounds.fRight -= pad;
bounds.fTop += pad;
bounds.fBottom -= pad;
this->drawRect(draw, bounds, paint);
}
virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
const SkPoint verts[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) SK_OVERRIDE {
this->drawPoints(draw, SkCanvas::kPolygon_PointMode, vertexCount, verts, paint);
}
virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) SK_OVERRIDE {
NothingToDo();
}
// TODO: allow this call to return failure, or move to SkBitmapDevice only.
virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
return fEmptyBitmap;
}
virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
return false;
}
private:
SkPictureUtils::SkPixelRefContainer* fPRCont;
SkISize fSize;
SkBitmap fEmptyBitmap; // legacy -- need to remove
static bool GetBitmapFromPaint(const SkPaint &paint, SkBitmap* bitmap) {
SkShader* shader = paint.getShader();
if (NULL != shader) {
if (SkShader::kNone_GradientType == shader->asAGradient(NULL)) {
return SkShader::kNone_BitmapType != shader->asABitmap(bitmap, NULL, NULL);
}
}
return false;
}
virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
NotSupported();
}
virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
// we expect to only get called via savelayer, in which case it is fine.
SkASSERT(kSaveLayer_Usage == usage);
return SkNEW_ARGS(SkGatherPixelRefsAndRectsDevice,
(info.width(), info.height(), fPRCont));
}
virtual void flush() SK_OVERRIDE {}
static void NotSupported() {
SkDEBUGFAIL("this method should never be called");
}
static void NothingToDo() {}
typedef SkBaseDevice INHERITED;
};
#endif // SkGatherPixelRefsAndRects_DEFINED