michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkLayerRasterizer.h" michael@0: #include "SkDraw.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: #include "SkMask.h" michael@0: #include "SkMaskFilter.h" michael@0: #include "SkPaint.h" michael@0: #include "SkPath.h" michael@0: #include "SkPathEffect.h" michael@0: #include "../core/SkRasterClip.h" michael@0: #include "SkXfermode.h" michael@0: #include michael@0: michael@0: struct SkLayerRasterizer_Rec { michael@0: SkPaint fPaint; michael@0: SkVector fOffset; michael@0: }; michael@0: michael@0: SkLayerRasterizer::SkLayerRasterizer() michael@0: : fLayers(SkNEW_ARGS(SkDeque, (sizeof(SkLayerRasterizer_Rec)))) michael@0: { michael@0: } michael@0: michael@0: SkLayerRasterizer::SkLayerRasterizer(SkDeque* layers) : fLayers(layers) michael@0: { michael@0: } michael@0: michael@0: SkLayerRasterizer::~SkLayerRasterizer() { michael@0: SkASSERT(fLayers); michael@0: SkDeque::F2BIter iter(*fLayers); michael@0: SkLayerRasterizer_Rec* rec; michael@0: michael@0: while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) michael@0: rec->fPaint.~SkPaint(); michael@0: michael@0: SkDELETE(fLayers); michael@0: } michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_LAYERRASTERIZER_API michael@0: void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, michael@0: SkScalar dy) { michael@0: SkASSERT(fLayers); michael@0: SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers->push_back(); michael@0: michael@0: SkNEW_PLACEMENT_ARGS(&rec->fPaint, SkPaint, (paint)); michael@0: rec->fOffset.set(dx, dy); michael@0: } michael@0: #endif michael@0: michael@0: static bool compute_bounds(const SkDeque& layers, const SkPath& path, michael@0: const SkMatrix& matrix, michael@0: const SkIRect* clipBounds, SkIRect* bounds) { michael@0: SkDeque::F2BIter iter(layers); michael@0: SkLayerRasterizer_Rec* rec; michael@0: michael@0: bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32); michael@0: michael@0: while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) { michael@0: const SkPaint& paint = rec->fPaint; michael@0: SkPath fillPath, devPath; michael@0: const SkPath* p = &path; michael@0: michael@0: if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { michael@0: paint.getFillPath(path, &fillPath); michael@0: p = &fillPath; michael@0: } michael@0: if (p->isEmpty()) { michael@0: continue; michael@0: } michael@0: michael@0: // apply the matrix and offset michael@0: { michael@0: SkMatrix m = matrix; michael@0: m.preTranslate(rec->fOffset.fX, rec->fOffset.fY); michael@0: p->transform(m, &devPath); michael@0: } michael@0: michael@0: SkMask mask; michael@0: if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(), michael@0: &matrix, &mask, michael@0: SkMask::kJustComputeBounds_CreateMode, michael@0: SkPaint::kFill_Style)) { michael@0: return false; michael@0: } michael@0: michael@0: bounds->join(mask.fBounds); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix, michael@0: const SkIRect* clipBounds, michael@0: SkMask* mask, SkMask::CreateMode mode) const { michael@0: SkASSERT(fLayers); michael@0: if (fLayers->empty()) { michael@0: return false; michael@0: } michael@0: michael@0: if (SkMask::kJustRenderImage_CreateMode != mode) { michael@0: if (!compute_bounds(*fLayers, path, matrix, clipBounds, &mask->fBounds)) michael@0: return false; michael@0: } michael@0: michael@0: if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { michael@0: mask->fFormat = SkMask::kA8_Format; michael@0: mask->fRowBytes = mask->fBounds.width(); michael@0: size_t size = mask->computeImageSize(); michael@0: if (0 == size) { michael@0: return false; // too big to allocate, abort michael@0: } michael@0: mask->fImage = SkMask::AllocImage(size); michael@0: memset(mask->fImage, 0, size); michael@0: } michael@0: michael@0: if (SkMask::kJustComputeBounds_CreateMode != mode) { michael@0: SkBitmap device; michael@0: SkRasterClip rectClip; michael@0: SkDraw draw; michael@0: SkMatrix translatedMatrix; // this translates us to our local pixels michael@0: SkMatrix drawMatrix; // this translates the path by each layer's offset michael@0: michael@0: rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height())); michael@0: michael@0: translatedMatrix = matrix; michael@0: translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft), michael@0: -SkIntToScalar(mask->fBounds.fTop)); michael@0: michael@0: device.installMaskPixels(*mask); michael@0: michael@0: draw.fBitmap = &device; michael@0: draw.fMatrix = &drawMatrix; michael@0: draw.fRC = &rectClip; michael@0: draw.fClip = &rectClip.bwRgn(); michael@0: // we set the matrixproc in the loop, as the matrix changes each time (potentially) michael@0: draw.fBounder = NULL; michael@0: michael@0: SkDeque::F2BIter iter(*fLayers); michael@0: SkLayerRasterizer_Rec* rec; michael@0: michael@0: while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) { michael@0: drawMatrix = translatedMatrix; michael@0: drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY); michael@0: draw.drawPath(path, rec->fPaint); michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: SkLayerRasterizer::SkLayerRasterizer(SkReadBuffer& buffer) michael@0: : SkRasterizer(buffer), fLayers(ReadLayers(buffer)) {} michael@0: michael@0: SkDeque* SkLayerRasterizer::ReadLayers(SkReadBuffer& buffer) { michael@0: int count = buffer.readInt(); michael@0: michael@0: SkDeque* layers = SkNEW_ARGS(SkDeque, (sizeof(SkLayerRasterizer_Rec))); michael@0: for (int i = 0; i < count; i++) { michael@0: SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)layers->push_back(); michael@0: michael@0: SkNEW_PLACEMENT(&rec->fPaint, SkPaint); michael@0: buffer.readPaint(&rec->fPaint); michael@0: buffer.readPoint(&rec->fOffset); michael@0: } michael@0: return layers; michael@0: } michael@0: michael@0: void SkLayerRasterizer::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: michael@0: SkASSERT(fLayers); michael@0: buffer.writeInt(fLayers->count()); michael@0: michael@0: SkDeque::F2BIter iter(*fLayers); michael@0: const SkLayerRasterizer_Rec* rec; michael@0: michael@0: while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL) { michael@0: buffer.writePaint(rec->fPaint); michael@0: buffer.writePoint(rec->fOffset); michael@0: } michael@0: } michael@0: michael@0: SkLayerRasterizer::Builder::Builder() michael@0: : fLayers(SkNEW_ARGS(SkDeque, (sizeof(SkLayerRasterizer_Rec)))) michael@0: { michael@0: } michael@0: michael@0: SkLayerRasterizer::Builder::~Builder() michael@0: { michael@0: SkDELETE(fLayers); michael@0: } michael@0: michael@0: void SkLayerRasterizer::Builder::addLayer(const SkPaint& paint, SkScalar dx, michael@0: SkScalar dy) { michael@0: SkASSERT(fLayers); michael@0: SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers->push_back(); michael@0: michael@0: SkNEW_PLACEMENT_ARGS(&rec->fPaint, SkPaint, (paint)); michael@0: rec->fOffset.set(dx, dy); michael@0: } michael@0: michael@0: SkLayerRasterizer* SkLayerRasterizer::Builder::detachRasterizer() { michael@0: SkLayerRasterizer* rasterizer = SkNEW_ARGS(SkLayerRasterizer, (fLayers)); michael@0: fLayers = NULL; michael@0: return rasterizer; michael@0: }