diff options
Diffstat (limited to 'src/core/SkDraw.cpp')
-rw-r--r-- | src/core/SkDraw.cpp | 2348 |
1 files changed, 0 insertions, 2348 deletions
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp deleted file mode 100644 index d59b813..0000000 --- a/src/core/SkDraw.cpp +++ /dev/null @@ -1,2348 +0,0 @@ -/* libs/graphics/sgl/SkDraw.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "SkDraw.h" -#include "SkBlitter.h" -#include "SkBounder.h" -#include "SkCanvas.h" -#include "SkColorPriv.h" -#include "SkDevice.h" -#include "SkMaskFilter.h" -#include "SkPaint.h" -#include "SkPathEffect.h" -#include "SkRasterizer.h" -#include "SkScan.h" -#include "SkShader.h" -#include "SkStroke.h" -#include "SkTemplatesPriv.h" -#include "SkUtils.h" - -#include "SkAutoKern.h" -#include "SkBitmapProcShader.h" -#include "SkDrawProcs.h" - -//#define TRACE_BITMAP_DRAWS - -class SkAutoRestoreBounder : SkNoncopyable { -public: - // note: initializing fBounder is done only to fix a warning - SkAutoRestoreBounder() : fDraw(NULL), fBounder(NULL) {} - ~SkAutoRestoreBounder() { - if (fDraw) { - fDraw->fBounder = fBounder; - } - } - - void clearBounder(const SkDraw* draw) { - fDraw = const_cast<SkDraw*>(draw); - fBounder = draw->fBounder; - fDraw->fBounder = NULL; - } - -private: - SkDraw* fDraw; - SkBounder* fBounder; -}; - -static SkPoint* rect_points(SkRect& r, int index) { - SkASSERT((unsigned)index < 2); - return &((SkPoint*)(void*)&r)[index]; -} - -/** Helper for allocating small blitters on the stack. -*/ - -#define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2) - -class SkAutoBlitterChoose { -public: - SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix, - const SkPaint& paint) { - fBlitter = SkBlitter::Choose(device, matrix, paint, - fStorage, sizeof(fStorage)); - } - ~SkAutoBlitterChoose(); - - SkBlitter* operator->() { return fBlitter; } - SkBlitter* get() const { return fBlitter; } - -private: - SkBlitter* fBlitter; - uint32_t fStorage[kBlitterStorageLongCount]; -}; - -SkAutoBlitterChoose::~SkAutoBlitterChoose() { - if ((void*)fBlitter == (void*)fStorage) { - fBlitter->~SkBlitter(); - } else { - SkDELETE(fBlitter); - } -} - -class SkAutoBitmapShaderInstall { -public: - SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint* paint) - : fPaint((SkPaint*)paint) { - fPrevShader = paint->getShader(); - fPrevShader->safeRef(); - fPaint->setShader(SkShader::CreateBitmapShader( src, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - fStorage, sizeof(fStorage))); - } - ~SkAutoBitmapShaderInstall() { - SkShader* shader = fPaint->getShader(); - - fPaint->setShader(fPrevShader); - fPrevShader->safeUnref(); - - if ((void*)shader == (void*)fStorage) { - shader->~SkShader(); - } else { - SkDELETE(shader); - } - } -private: - SkPaint* fPaint; - SkShader* fPrevShader; - uint32_t fStorage[kBlitterStorageLongCount]; -}; - -class SkAutoPaintStyleRestore { -public: - SkAutoPaintStyleRestore(const SkPaint& paint, SkPaint::Style style) - : fPaint((SkPaint&)paint) { - fStyle = paint.getStyle(); // record the old - fPaint.setStyle(style); // change it to the specified style - } - ~SkAutoPaintStyleRestore() { - fPaint.setStyle(fStyle); // restore the old - } -private: - SkPaint& fPaint; - SkPaint::Style fStyle; - - // illegal - SkAutoPaintStyleRestore(const SkAutoPaintStyleRestore&); - SkAutoPaintStyleRestore& operator=(const SkAutoPaintStyleRestore&); -}; - -/////////////////////////////////////////////////////////////////////////////// - -SkDraw::SkDraw(const SkDraw& src) { - memcpy(this, &src, sizeof(*this)); -} - -/////////////////////////////////////////////////////////////////////////////// - -typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); - -static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { - bzero(pixels, bytes); -} - -static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} - -static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { - sk_memset32((uint32_t*)pixels, data, bytes >> 2); -} - -static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { - sk_memset16((uint16_t*)pixels, data, bytes >> 1); -} - -static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { - memset(pixels, data, bytes); -} - -static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap, - const SkPaint& paint, - uint32_t* data) { - // todo: we can apply colorfilter up front if no shader, so we wouldn't - // need to abort this fastpath - if (paint.getShader() || paint.getColorFilter()) { - return NULL; - } - - SkPorterDuff::Mode mode; - if (!SkPorterDuff::IsMode(paint.getXfermode(), &mode)) { - return NULL; - } - - SkColor color = paint.getColor(); - - // collaps modes based on color... - if (SkPorterDuff::kSrcOver_Mode == mode) { - unsigned alpha = SkColorGetA(color); - if (0 == alpha) { - mode = SkPorterDuff::kDst_Mode; - } else if (0xFF == alpha) { - mode = SkPorterDuff::kSrc_Mode; - } - } - - switch (mode) { - case SkPorterDuff::kClear_Mode: -// SkDebugf("--- D_Clear_BitmapXferProc\n"); - return D_Clear_BitmapXferProc; // ignore data - case SkPorterDuff::kDst_Mode: -// SkDebugf("--- D_Dst_BitmapXferProc\n"); - return D_Dst_BitmapXferProc; // ignore data - case SkPorterDuff::kSrc_Mode: { - /* - should I worry about dithering for the lower depths? - */ - SkPMColor pmc = SkPreMultiplyColor(color); - switch (bitmap.config()) { - case SkBitmap::kARGB_8888_Config: - if (data) { - *data = pmc; - } -// SkDebugf("--- D32_Src_BitmapXferProc\n"); - return D32_Src_BitmapXferProc; - case SkBitmap::kARGB_4444_Config: - if (data) { - *data = SkPixel32ToPixel4444(pmc); - } -// SkDebugf("--- D16_Src_BitmapXferProc\n"); - return D16_Src_BitmapXferProc; - case SkBitmap::kRGB_565_Config: - if (data) { - *data = SkPixel32ToPixel16(pmc); - } -// SkDebugf("--- D16_Src_BitmapXferProc\n"); - return D16_Src_BitmapXferProc; - case SkBitmap::kA8_Config: - if (data) { - *data = SkGetPackedA32(pmc); - } -// SkDebugf("--- DA8_Src_BitmapXferProc\n"); - return DA8_Src_BitmapXferProc; - default: - break; - } - break; - } - default: - break; - } - return NULL; -} - -static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect, - BitmapXferProc proc, uint32_t procData) { - int shiftPerPixel; - switch (bitmap.config()) { - case SkBitmap::kARGB_8888_Config: - shiftPerPixel = 2; - break; - case SkBitmap::kARGB_4444_Config: - case SkBitmap::kRGB_565_Config: - shiftPerPixel = 1; - break; - case SkBitmap::kA8_Config: - shiftPerPixel = 0; - break; - default: - SkASSERT(!"Can't use xferproc on this config"); - return; - } - - uint8_t* pixels = (uint8_t*)bitmap.getPixels(); - SkASSERT(pixels); - const size_t rowBytes = bitmap.rowBytes(); - const int widthBytes = rect.width() << shiftPerPixel; - - // skip down to the first scanline and X position - pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); - for (int scans = rect.height() - 1; scans >= 0; --scans) { - proc(pixels, widthBytes, procData); - pixels += rowBytes; - } -} - -void SkDraw::drawPaint(const SkPaint& paint) const { - SkDEBUGCODE(this->validate();) - - if (fClip->isEmpty()) { - return; - } - - SkIRect devRect; - devRect.set(0, 0, fBitmap->width(), fBitmap->height()); - if (fBounder && !fBounder->doIRect(devRect)) { - return; - } - - /* If we don't have a shader (i.e. we're just a solid color) we may - be faster to operate directly on the device bitmap, rather than invoking - a blitter. Esp. true for xfermodes, which require a colorshader to be - present, which is just redundant work. Since we're drawing everywhere - in the clip, we don't have to worry about antialiasing. - */ - uint32_t procData = 0; // to avoid the warning - BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData); - if (proc) { - if (D_Dst_BitmapXferProc == proc) { // nothing to do - return; - } - - SkRegion::Iterator iter(*fClip); - while (!iter.done()) { - CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData); - iter.next(); - } - } else { - // normal case: use a blitter - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - SkScan::FillIRect(devRect, fClip, blitter.get()); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -struct PtProcRec { - SkCanvas::PointMode fMode; - const SkPaint* fPaint; - const SkRegion* fClip; - - // computed values - SkFixed fRadius; - - typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, - SkBlitter*); - - bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, - const SkRegion* clip); - Proc chooseProc(SkBlitter* blitter); -}; - -static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - SkASSERT(rec.fClip->isRect()); - const SkIRect& r = rec.fClip->getBounds(); - - for (int i = 0; i < count; i++) { - int x = SkScalarFloor(devPts[i].fX); - int y = SkScalarFloor(devPts[i].fY); - if (r.contains(x, y)) { - blitter->blitH(x, y, 1); - } - } -} - -static void bw_pt_rect_16_hair_proc(const PtProcRec& rec, - const SkPoint devPts[], int count, - SkBlitter* blitter) { - SkASSERT(rec.fClip->isRect()); - const SkIRect& r = rec.fClip->getBounds(); - uint32_t value; - const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value); - SkASSERT(bitmap); - - uint16_t* addr = bitmap->getAddr16(0, 0); - int rb = bitmap->rowBytes(); - - for (int i = 0; i < count; i++) { - int x = SkScalarFloor(devPts[i].fX); - int y = SkScalarFloor(devPts[i].fY); - if (r.contains(x, y)) { -// *bitmap->getAddr16(x, y) = SkToU16(value); - ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); - } - } -} - -static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - for (int i = 0; i < count; i++) { - int x = SkScalarFloor(devPts[i].fX); - int y = SkScalarFloor(devPts[i].fY); - if (rec.fClip->contains(x, y)) { - blitter->blitH(x, y, 1); - } - } -} - -static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - for (int i = 0; i < count; i += 2) { - SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter); - } -} - -static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - for (int i = 0; i < count - 1; i++) { - SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter); - } -} - -// aa versions - -static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - for (int i = 0; i < count; i += 2) { - SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter); - } -} - -static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - for (int i = 0; i < count - 1; i++) { - SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter); - } -} - -// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) - -static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - const SkFixed radius = rec.fRadius; - for (int i = 0; i < count; i++) { - SkFixed x = SkScalarToFixed(devPts[i].fX); - SkFixed y = SkScalarToFixed(devPts[i].fY); - - SkXRect r; - r.fLeft = x - radius; - r.fTop = y - radius; - r.fRight = x + radius; - r.fBottom = y + radius; - - SkScan::FillXRect(r, rec.fClip, blitter); - } -} - -static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], - int count, SkBlitter* blitter) { - const SkFixed radius = rec.fRadius; - for (int i = 0; i < count; i++) { - SkFixed x = SkScalarToFixed(devPts[i].fX); - SkFixed y = SkScalarToFixed(devPts[i].fY); - - SkXRect r; - r.fLeft = x - radius; - r.fTop = y - radius; - r.fRight = x + radius; - r.fBottom = y + radius; - - SkScan::AntiFillXRect(r, rec.fClip, blitter); - } -} - -bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, - const SkMatrix* matrix, const SkRegion* clip) { - if (paint.getPathEffect()) { - return false; - } - SkScalar width = paint.getStrokeWidth(); - if (0 == width) { - fMode = mode; - fPaint = &paint; - fClip = clip; - fRadius = SK_Fixed1 >> 1; - return true; - } - if (matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) { - SkScalar sx = matrix->get(SkMatrix::kMScaleX); - SkScalar sy = matrix->get(SkMatrix::kMScaleY); - if (SkScalarNearlyZero(sx - sy)) { - if (sx < 0) { - sx = -sx; - } - - fMode = mode; - fPaint = &paint; - fClip = clip; - fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; - return true; - } - } - return false; -} - -PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) { - Proc proc; - - // for our arrays - SkASSERT(0 == SkCanvas::kPoints_PointMode); - SkASSERT(1 == SkCanvas::kLines_PointMode); - SkASSERT(2 == SkCanvas::kPolygon_PointMode); - SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); - - // first check for hairlines - if (0 == fPaint->getStrokeWidth()) { - if (fPaint->isAntiAlias()) { - static const Proc gAAProcs[] = { - aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc - }; - proc = gAAProcs[fMode]; - } else { - if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { - uint32_t value; - const SkBitmap* bm = blitter->justAnOpaqueColor(&value); - if (bm && bm->config() == SkBitmap::kRGB_565_Config) { - proc = bw_pt_rect_16_hair_proc; - } else { - proc = bw_pt_rect_hair_proc; - } - } else { - static Proc gBWProcs[] = { - bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc - }; - proc = gBWProcs[fMode]; - } - } - } else { - SkASSERT(SkCanvas::kPoints_PointMode == fMode); - if (fPaint->isAntiAlias()) { - proc = aa_square_proc; - } else { - proc = bw_square_proc; - } - } - return proc; -} - -static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode, - size_t count, const SkPoint pts[], - const SkPaint& paint, const SkMatrix& matrix) { - SkIRect ibounds; - SkRect bounds; - SkScalar inset = paint.getStrokeWidth(); - - bounds.set(pts, count); - bounds.inset(-inset, -inset); - matrix.mapRect(&bounds); - - bounds.roundOut(&ibounds); - return bounder->doIRect(ibounds); -} - -// each of these costs 8-bytes of stack space, so don't make it too large -// must be even for lines/polygon to work -#define MAX_DEV_PTS 32 - -void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, - const SkPoint pts[], const SkPaint& paint) const { - // if we're in lines mode, force count to be even - if (SkCanvas::kLines_PointMode == mode) { - count &= ~(size_t)1; - } - - if ((long)count <= 0) { - return; - } - - SkAutoRestoreBounder arb; - - if (fBounder) { - if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) { - return; - } - // clear the bounder for the rest of this function, so we don't call it - // again later if we happen to call ourselves for drawRect, drawPath, - // etc. - arb.clearBounder(this); - } - - SkASSERT(pts != NULL); - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - PtProcRec rec; - if (rec.init(mode, paint, fMatrix, fClip)) { - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - - SkPoint devPts[MAX_DEV_PTS]; - const SkMatrix* matrix = fMatrix; - SkBlitter* bltr = blitter.get(); - PtProcRec::Proc proc = rec.chooseProc(bltr); - // we have to back up subsequent passes if we're in polygon mode - const size_t backup = (SkCanvas::kPolygon_PointMode == mode); - - do { - size_t n = count; - if (n > MAX_DEV_PTS) { - n = MAX_DEV_PTS; - } - matrix->mapPoints(devPts, pts, n); - proc(rec, devPts, n, bltr); - pts += n - backup; - SkASSERT(count >= n); - count -= n; - if (count > 0) { - count += backup; - } - } while (count != 0); - } else { - switch (mode) { - case SkCanvas::kPoints_PointMode: { - // temporarily mark the paint as filling. - SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style); - - SkScalar width = paint.getStrokeWidth(); - SkScalar radius = SkScalarHalf(width); - - if (paint.getStrokeCap() == SkPaint::kRound_Cap) { - SkPath path; - SkMatrix preMatrix; - - path.addCircle(0, 0, radius); - for (size_t i = 0; i < count; i++) { - preMatrix.setTranslate(pts[i].fX, pts[i].fY); - // pass true for the last point, since we can modify - // then path then - this->drawPath(path, paint, &preMatrix, (count-1) == i); - } - } else { - SkRect r; - - for (size_t i = 0; i < count; i++) { - r.fLeft = pts[i].fX - radius; - r.fTop = pts[i].fY - radius; - r.fRight = r.fLeft + width; - r.fBottom = r.fTop + width; - this->drawRect(r, paint); - } - } - break; - } - case SkCanvas::kLines_PointMode: - case SkCanvas::kPolygon_PointMode: { - count -= 1; - SkPath path; - SkPaint p(paint); - p.setStyle(SkPaint::kStroke_Style); - size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; - for (size_t i = 0; i < count; i += inc) { - path.moveTo(pts[i]); - path.lineTo(pts[i+1]); - this->drawPath(path, p, NULL, true); - path.rewind(); - } - break; - } - } - } -} - -static inline SkPoint* as_lefttop(SkRect* r) { - return (SkPoint*)(void*)r; -} - -static inline SkPoint* as_rightbottom(SkRect* r) { - return ((SkPoint*)(void*)r) + 1; -} - -void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - // complex enough to draw as a path - if (paint.getPathEffect() || paint.getMaskFilter() || - paint.getRasterizer() || !fMatrix->rectStaysRect() || - (paint.getStyle() != SkPaint::kFill_Style && - SkScalarHalf(paint.getStrokeWidth()) > 0)) { - SkPath tmp; - tmp.addRect(rect); - tmp.setFillType(SkPath::kWinding_FillType); - this->drawPath(tmp, paint); - return; - } - - const SkMatrix& matrix = *fMatrix; - SkRect devRect; - - // transform rect into devRect - { - matrix.mapXY(rect.fLeft, rect.fTop, rect_points(devRect, 0)); - matrix.mapXY(rect.fRight, rect.fBottom, rect_points(devRect, 1)); - devRect.sort(); - } - - if (fBounder && !fBounder->doRect(devRect, paint)) { - return; - } - - // look for the quick exit, before we build a blitter - { - SkIRect ir; - devRect.roundOut(&ir); - if (fClip->quickReject(ir)) - return; - } - - SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint); - SkBlitter* blitter = blitterStorage.get(); - const SkRegion* clip = fClip; - - if (paint.getStyle() == SkPaint::kFill_Style) { - if (paint.isAntiAlias()) { - SkScan::AntiFillRect(devRect, clip, blitter); - } else { - SkScan::FillRect(devRect, clip, blitter); - } - } else { - if (paint.isAntiAlias()) { - SkScan::AntiHairRect(devRect, clip, blitter); - } else { - SkScan::HairRect(devRect, clip, blitter); - } - } -} - -void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { - if (srcM.fBounds.isEmpty()) { - return; - } - - SkMask dstM; - const SkMask* mask = &srcM; - - dstM.fImage = NULL; - SkAutoMaskImage ami(&dstM, false); - - if (paint.getMaskFilter() && - paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) { - mask = &dstM; - } - - if (fBounder && !fBounder->doIRect(mask->fBounds)) { - return; - } - - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - - blitter->blitMaskRegion(*mask, *fClip); -} - -class SkAutoPaintRestoreColorStrokeWidth { -public: - SkAutoPaintRestoreColorStrokeWidth(const SkPaint& paint) { - fPaint = (SkPaint*)&paint; - fColor = paint.getColor(); - fWidth = paint.getStrokeWidth(); - } - ~SkAutoPaintRestoreColorStrokeWidth() { - fPaint->setColor(fColor); - fPaint->setStrokeWidth(fWidth); - } - -private: - SkPaint* fPaint; - SkColor fColor; - SkScalar fWidth; -}; - -void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint, - const SkMatrix* prePathMatrix, bool pathIsMutable) const { - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - SkPath* pathPtr = (SkPath*)&origSrcPath; - bool doFill = true; - SkPath tmpPath; - SkMatrix tmpMatrix; - const SkMatrix* matrix = fMatrix; - - if (prePathMatrix) { - if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style || - paint.getRasterizer()) { - SkPath* result = pathPtr; - - if (!pathIsMutable) { - result = &tmpPath; - pathIsMutable = true; - } - pathPtr->transform(*prePathMatrix, result); - pathPtr = result; - } else { - if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) { - // overflow - return; - } - matrix = &tmpMatrix; - } - } - // at this point we're done with prePathMatrix - SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) - - /* - If the device thickness < 1.0, then make it a hairline, and - modulate alpha if the thickness is even smaller (e.g. thickness == 0.5 - should modulate the alpha by 1/2) - */ - - SkAutoPaintRestoreColorStrokeWidth aprc(paint); - - if (paint.getStyle() == SkPaint::kStroke_Style && - paint.getXfermode() == NULL && - (matrix->getType() & SkMatrix::kPerspective_Mask) == 0) { - SkScalar width = paint.getStrokeWidth(); - if (width > 0) { - width = matrix->mapRadius(paint.getStrokeWidth()); - if (width < SK_Scalar1) { - int scale = (int)SkScalarMul(width, 256); - int alpha = paint.getAlpha() * scale >> 8; - - // pretend to be a hairline, with a modulated alpha - ((SkPaint*)&paint)->setAlpha(alpha); - ((SkPaint*)&paint)->setStrokeWidth(0); - -// SkDebugf("------ convert to hairline %d\n", scale); - } - } - } - - if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { - doFill = paint.getFillPath(*pathPtr, &tmpPath); - pathPtr = &tmpPath; - } - - if (paint.getRasterizer()) { - SkMask mask; - if (paint.getRasterizer()->rasterize(*pathPtr, *matrix, - &fClip->getBounds(), paint.getMaskFilter(), &mask, - SkMask::kComputeBoundsAndRenderImage_CreateMode)) { - this->drawDevMask(mask, paint); - SkMask::FreeImage(mask.fImage); - } - return; - } - - // avoid possibly allocating a new path in transform if we can - SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; - - // transform the path into device space - pathPtr->transform(*matrix, devPathPtr); - - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - - // how does filterPath() know to fill or hairline the path??? <mrr> - if (paint.getMaskFilter() && - paint.getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fClip, - fBounder, blitter.get())) { - return; // filterPath() called the blitter, so we're done - } - - if (fBounder && !fBounder->doPath(*devPathPtr, paint, doFill)) { - return; - } - - if (doFill) { - if (paint.isAntiAlias()) { - SkScan::AntiFillPath(*devPathPtr, *fClip, blitter.get()); - } else { - SkScan::FillPath(*devPathPtr, *fClip, blitter.get()); - } - } else { // hairline - if (paint.isAntiAlias()) { - SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get()); - } else { - SkScan::HairPath(*devPathPtr, fClip, blitter.get()); - } - } -} - -static inline bool just_translate(const SkMatrix& m) { - return (m.getType() & ~SkMatrix::kTranslate_Mask) == 0; -} - -void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, - const SkPaint& paint) const { - SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config); - - if (just_translate(*fMatrix)) { - int ix = SkScalarRound(fMatrix->getTranslateX()); - int iy = SkScalarRound(fMatrix->getTranslateY()); - - SkMask mask; - mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); - mask.fFormat = SkMask::kA8_Format; - mask.fRowBytes = bitmap.rowBytes(); - mask.fImage = bitmap.getAddr8(0, 0); - - this->drawDevMask(mask, paint); - } else { // need to xform the bitmap first - SkRect r; - SkMask mask; - - r.set(0, 0, - SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); - fMatrix->mapRect(&r); - r.round(&mask.fBounds); - - // set the mask's bounds to the transformed bitmap-bounds, - // clipped to the actual device - { - SkIRect devBounds; - devBounds.set(0, 0, fBitmap->width(), fBitmap->height()); - // need intersect(l, t, r, b) on irect - if (!mask.fBounds.intersect(devBounds)) { - return; - } - } - mask.fFormat = SkMask::kA8_Format; - mask.fRowBytes = SkAlign4(mask.fBounds.width()); - - // allocate (and clear) our temp buffer to hold the transformed bitmap - size_t size = mask.computeImageSize(); - SkAutoMalloc storage(size); - mask.fImage = (uint8_t*)storage.get(); - memset(mask.fImage, 0, size); - - // now draw our bitmap(src) into mask(dst), transformed by the matrix - { - SkBitmap device; - device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), - mask.fBounds.height(), mask.fRowBytes); - device.setPixels(mask.fImage); - - SkCanvas c(device); - // need the unclipped top/left for the translate - c.translate(-SkIntToScalar(mask.fBounds.fLeft), - -SkIntToScalar(mask.fBounds.fTop)); - c.concat(*fMatrix); - c.drawBitmap(bitmap, 0, 0, NULL); - } - this->drawDevMask(mask, paint); - } -} - -static bool clipped_out(const SkMatrix& m, const SkRegion& c, - const SkRect& srcR) { - SkRect dstR; - SkIRect devIR; - - m.mapRect(&dstR, srcR); - dstR.roundOut(&devIR); - return c.quickReject(devIR); -} - -static bool clipped_out(const SkMatrix& matrix, const SkRegion& clip, - int width, int height) { - SkRect r; - r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); - return clipped_out(matrix, clip, r); -} - -void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, - const SkPaint& paint) const { - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (fClip->isEmpty() || - bitmap.width() == 0 || bitmap.height() == 0 || - bitmap.getConfig() == SkBitmap::kNo_Config || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - // run away on too-big bitmaps for now (exceed 16.16) - if (bitmap.width() > 32767 || bitmap.height() > 32767) { - return; - } - - SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style); - - SkMatrix matrix; - if (!matrix.setConcat(*fMatrix, prematrix)) { - return; - } - - // do I need to call the bounder first??? - if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) { - return; - } - - // only lock the pixels if we passed the clip test - SkAutoLockPixels alp(bitmap); - // after the lock, check if we are valid - if (!bitmap.readyToDraw()) { - return; - } - - if (bitmap.getConfig() != SkBitmap::kA8_Config && just_translate(matrix)) { - int ix = SkScalarRound(matrix.getTranslateX()); - int iy = SkScalarRound(matrix.getTranslateY()); - uint32_t storage[kBlitterStorageLongCount]; - SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, - ix, iy, storage, sizeof(storage)); - if (blitter) { - SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); - - SkIRect ir; - ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); - - if (fBounder && !fBounder->doIRect(ir)) { - return; - } - - SkRegion::Cliperator iter(*fClip, ir); - const SkIRect& cr = iter.rect(); - - for (; !iter.done(); iter.next()) { - SkASSERT(!cr.isEmpty()); - blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height()); - } - return; - } -#if 0 - SkDebugf("---- MISSING sprite case: config=%d [%d %d], device=%d, xfer=%p, alpha=0x%X colorFilter=%p\n", - bitmap.config(), bitmap.width(), bitmap.height(), fBitmap->config(), - paint.getXfermode(), paint.getAlpha(), paint.getColorFilter()); -#endif - } - - // now make a temp draw on the stack, and use it - // - SkDraw draw(*this); - draw.fMatrix = &matrix; - - if (bitmap.getConfig() == SkBitmap::kA8_Config) { - draw.drawBitmapAsMask(bitmap, paint); - } else { - SkAutoBitmapShaderInstall install(bitmap, &paint); - - SkRect r; - r.set(0, 0, SkIntToScalar(bitmap.width()), - SkIntToScalar(bitmap.height())); - // is this ok if paint has a rasterizer? - draw.drawRect(r, paint); - } -} - -void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, - const SkPaint& paint) const { - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (fClip->isEmpty() || - bitmap.width() == 0 || bitmap.height() == 0 || - bitmap.getConfig() == SkBitmap::kNo_Config || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - SkIRect bounds; - bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); - - if (fClip->quickReject(bounds)) { - return; // nothing to draw - } - - SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style); - - if (NULL == paint.getColorFilter()) { - uint32_t storage[kBlitterStorageLongCount]; - SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, - x, y, storage, sizeof(storage)); - - if (blitter) { - SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); - - if (fBounder && !fBounder->doIRect(bounds)) { - return; - } - - SkRegion::Cliperator iter(*fClip, bounds); - const SkIRect& cr = iter.rect(); - - for (; !iter.done(); iter.next()) { - SkASSERT(!cr.isEmpty()); - blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height()); - } - return; - } - } - - SkAutoBitmapShaderInstall install(bitmap, &paint); - - SkMatrix matrix; - SkRect r; - - // get a scalar version of our rect - r.set(bounds); - - // tell the shader our offset - matrix.setTranslate(r.fLeft, r.fTop); - paint.getShader()->setLocalMatrix(matrix); - - SkDraw draw(*this); - matrix.reset(); - draw.fMatrix = &matrix; - // call ourself with a rect - // is this OK if paint has a rasterizer? - draw.drawRect(r, paint); -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkScalerContext.h" -#include "SkGlyphCache.h" -#include "SkUtils.h" - -static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, - const char text[], size_t byteLength, SkVector* stopVector) { - SkFixed x = 0, y = 0; - const char* stop = text + byteLength; - - SkAutoKern autokern; - - while (text < stop) { - // don't need x, y here, since all subpixel variants will have the - // same advance - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - - x += autokern.adjust(glyph) + glyph.fAdvanceX; - y += glyph.fAdvanceY; - } - stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); - - SkASSERT(text == stop); -} - -void SkDraw::drawText_asPaths(const char text[], size_t byteLength, - SkScalar x, SkScalar y, - const SkPaint& paint) const { - SkDEBUGCODE(this->validate();) - - SkTextToPathIter iter(text, byteLength, paint, true, true); - - SkMatrix matrix; - matrix.setScale(iter.getPathScale(), iter.getPathScale()); - matrix.postTranslate(x, y); - - const SkPath* iterPath; - SkScalar xpos, prevXPos = 0; - - while ((iterPath = iter.next(&xpos)) != NULL) { - matrix.postTranslate(xpos - prevXPos, 0); - this->drawPath(*iterPath, iter.getPaint(), &matrix, false); - prevXPos = xpos; - } -} - -#define kStdStrikeThru_Offset (-SK_Scalar1 * 6 / 21) -#define kStdUnderline_Offset (SK_Scalar1 / 9) -#define kStdUnderline_Thickness (SK_Scalar1 / 18) - -static void draw_paint_rect(const SkDraw* draw, const SkPaint& paint, - const SkRect& r, SkScalar textSize) { - if (paint.getStyle() == SkPaint::kFill_Style) { - draw->drawRect(r, paint); - } else { - SkPaint p(paint); - p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); - draw->drawRect(r, p); - } -} - -static void handle_aftertext(const SkDraw* draw, const SkPaint& paint, - SkScalar width, const SkPoint& start) { - uint32_t flags = paint.getFlags(); - - if (flags & (SkPaint::kUnderlineText_Flag | - SkPaint::kStrikeThruText_Flag)) { - SkScalar textSize = paint.getTextSize(); - SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); - SkRect r; - - r.fLeft = start.fX; - r.fRight = start.fX + width; - - if (flags & SkPaint::kUnderlineText_Flag) { - SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, - start.fY); - r.fTop = offset; - r.fBottom = offset + height; - draw_paint_rect(draw, paint, r, textSize); - } - if (flags & SkPaint::kStrikeThruText_Flag) { - SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, - start.fY); - r.fTop = offset; - r.fBottom = offset + height; - draw_paint_rect(draw, paint, r, textSize); - } - } -} - -// disable warning : local variable used without having been initialized -#if defined _WIN32 && _MSC_VER >= 1300 -#pragma warning ( push ) -#pragma warning ( disable : 4701 ) -#endif - -////////////////////////////////////////////////////////////////////////////// - -static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, - const SkGlyph& glyph, int left, int top) { - SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); - SkASSERT(state.fClip->isRect()); - SkASSERT(NULL == state.fBounder); - SkASSERT(state.fClipBounds == state.fClip->getBounds()); - - left += glyph.fLeft; - top += glyph.fTop; - - int right = left + glyph.fWidth; - int bottom = top + glyph.fHeight; - - SkMask mask; - SkIRect storage; - SkIRect* bounds = &mask.fBounds; - - mask.fBounds.set(left, top, right, bottom); - - // this extra test is worth it, assuming that most of the time it succeeds - // since we can avoid writing to storage - if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { - if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) - return; - bounds = &storage; - } - - uint8_t* aa = (uint8_t*)glyph.fImage; - if (NULL == aa) { - aa = (uint8_t*)state.fCache->findImage(glyph); - if (NULL == aa) { - return; // can't rasterize glyph - } - } - - mask.fRowBytes = glyph.rowBytes(); - mask.fFormat = glyph.fMaskFormat; - mask.fImage = aa; - state.fBlitter->blitMask(mask, *bounds); -} - -static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, - const SkGlyph& glyph, int left, int top) { - SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); - SkASSERT(!state.fClip->isRect()); - SkASSERT(NULL == state.fBounder); - - SkMask mask; - - left += glyph.fLeft; - top += glyph.fTop; - - mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); - SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); - - if (!clipper.done()) { - const SkIRect& cr = clipper.rect(); - const uint8_t* aa = (const uint8_t*)glyph.fImage; - if (NULL == aa) { - aa = (uint8_t*)state.fCache->findImage(glyph); - if (NULL == aa) { - return; - } - } - - mask.fRowBytes = glyph.rowBytes(); - mask.fFormat = glyph.fMaskFormat; - mask.fImage = (uint8_t*)aa; - do { - state.fBlitter->blitMask(mask, cr); - clipper.next(); - } while (!clipper.done()); - } -} - -static void D1G_Bounder(const SkDraw1Glyph& state, - const SkGlyph& glyph, int left, int top) { - SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); - - SkMask mask; - - left += glyph.fLeft; - top += glyph.fTop; - - mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); - SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); - - if (!clipper.done()) { - const SkIRect& cr = clipper.rect(); - const uint8_t* aa = (const uint8_t*)glyph.fImage; - if (NULL == aa) { - aa = (uint8_t*)state.fCache->findImage(glyph); - if (NULL == aa) { - return; - } - } - - if (state.fBounder->doIRect(cr)) { - mask.fRowBytes = glyph.rowBytes(); - mask.fFormat = glyph.fMaskFormat; - mask.fImage = (uint8_t*)aa; - do { - state.fBlitter->blitMask(mask, cr); - clipper.next(); - } while (!clipper.done()); - } - } -} - -SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, - SkGlyphCache* cache) { - fDraw = draw; - fBounder = draw->fBounder; - fClip = draw->fClip; - fClipBounds = fClip->getBounds(); - fBlitter = blitter; - fCache = cache; - - if (draw->fProcs && draw->fProcs->fD1GProc) { - return draw->fProcs->fD1GProc; - } - - if (NULL == fBounder) { - if (fClip->isRect()) { - return D1G_NoBounder_RectClip; - } else { - return D1G_NoBounder_RgnClip; - } - } else { - return D1G_Bounder; - } -} - -enum RoundBaseline { - kDont_Round_Baseline, - kRound_X_Baseline, - kRound_Y_Baseline -}; - -static RoundBaseline computeRoundBaseline(const SkMatrix& mat) { - if (mat[1] == 0 && mat[3] == 0) { - // we're 0 or 180 degrees, round the y coordinate of the baseline - return kRound_Y_Baseline; - } else if (mat[0] == 0 && mat[4] == 0) { - // we're 90 or 270 degrees, round the x coordinate of the baseline - return kRound_X_Baseline; - } else { - return kDont_Round_Baseline; - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void SkDraw::drawText(const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkPaint& paint) const { - SkASSERT(byteLength == 0 || text != NULL); - - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (text == NULL || byteLength == 0 || - fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - SkScalar underlineWidth = 0; - SkPoint underlineStart; - - underlineStart.set(0, 0); // to avoid warning - if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | - SkPaint::kStrikeThruText_Flag)) { - underlineWidth = paint.measureText(text, byteLength); - - SkScalar offsetX = 0; - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - offsetX = SkScalarHalf(underlineWidth); - } else if (paint.getTextAlign() == SkPaint::kRight_Align) { - offsetX = underlineWidth; - } - underlineStart.set(x - offsetX, y); - } - - if (/*paint.isLinearText() ||*/ - (fMatrix->getType() & SkMatrix::kPerspective_Mask)) { - this->drawText_asPaths(text, byteLength, x, y, paint); - handle_aftertext(this, paint, underlineWidth, underlineStart); - return; - } - - SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); - - SkAutoGlyphCache autoCache(paint, fMatrix); - SkGlyphCache* cache = autoCache.getCache(); - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - - // transform our starting point - { - SkPoint loc; - fMatrix->mapXY(x, y, &loc); - x = loc.fX; - y = loc.fY; - } - - // need to measure first - if (paint.getTextAlign() != SkPaint::kLeft_Align) { - SkVector stop; - - measure_text(cache, glyphCacheProc, text, byteLength, &stop); - - SkScalar stopX = stop.fX; - SkScalar stopY = stop.fY; - - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - stopX = SkScalarHalf(stopX); - stopY = SkScalarHalf(stopY); - } - x -= stopX; - y -= stopY; - } - - SkFixed fx = SkScalarToFixed(x); - SkFixed fy = SkScalarToFixed(y); - const char* stop = text + byteLength; - - if (paint.isSubpixelText()) { - RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix); - if (kRound_Y_Baseline == roundBaseline) { - fy = (fy + 0x8000) & ~0xFFFF; - } else if (kRound_X_Baseline == roundBaseline) { - fx = (fx + 0x8000) & ~0xFFFF; - } - } else { - // apply the bias here, so we don't have to add 1/2 in the loop - fx += SK_Fixed1/2; - fy += SK_Fixed1/2; - } - - SkAutoKern autokern; - SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache); - - while (text < stop) { - const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy); - - fx += autokern.adjust(glyph); - - if (glyph.fWidth) { - proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy)); - } - fx += glyph.fAdvanceX; - fy += glyph.fAdvanceY; - } - - if (underlineWidth) { - autoCache.release(); // release this now to free up the RAM - handle_aftertext(this, paint, underlineWidth, underlineStart); - } -} - -// last parameter is interpreted as SkFixed [x, y] -// return the fixed position, which may be rounded or not by the caller -// e.g. subpixel doesn't round -typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); - -static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, - SkIPoint* dst) { - dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); -} - -static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, - SkIPoint* dst) { - dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), - SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); -} - -static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, - SkIPoint* dst) { - dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, - SkScalarToFixed(loc.fY) - glyph.fAdvanceY); -} - -static AlignProc pick_align_proc(SkPaint::Align align) { - static const AlignProc gProcs[] = { - leftAlignProc, centerAlignProc, rightAlignProc - }; - - SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); - - return gProcs[align]; -} - -class TextMapState { -public: - mutable SkPoint fLoc; - - TextMapState(const SkMatrix& matrix, SkScalar y) - : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} - - typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); - - Proc pickProc(int scalarsPerPosition); - -private: - const SkMatrix& fMatrix; - SkMatrix::MapXYProc fProc; - SkScalar fY; // ignored by MapXYProc - // these are only used by Only... procs - SkScalar fScaleX, fTransX, fTransformedY; - - static void MapXProc(const TextMapState& state, const SkScalar pos[]) { - state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); - } - - static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { - state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); - } - - static void MapOnlyScaleXProc(const TextMapState& state, - const SkScalar pos[]) { - state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, - state.fTransformedY); - } - - static void MapOnlyTransXProc(const TextMapState& state, - const SkScalar pos[]) { - state.fLoc.set(*pos + state.fTransX, state.fTransformedY); - } -}; - -TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { - SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); - - if (1 == scalarsPerPosition) { - unsigned mtype = fMatrix.getType(); - if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { - return MapXProc; - } else { - fScaleX = fMatrix.getScaleX(); - fTransX = fMatrix.getTranslateX(); - fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + - fMatrix.getTranslateY(); - return (mtype & SkMatrix::kScale_Mask) ? - MapOnlyScaleXProc : MapOnlyTransXProc; - } - } else { - return MapXYProc; - } -} - -////////////////////////////////////////////////////////////////////////////// - -void SkDraw::drawPosText(const char text[], size_t byteLength, - const SkScalar pos[], SkScalar constY, - int scalarsPerPosition, const SkPaint& paint) const { - SkASSERT(byteLength == 0 || text != NULL); - SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); - - SkDEBUGCODE(this->validate();) - - // nothing to draw - if (text == NULL || byteLength == 0 || - fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - if (/*paint.isLinearText() ||*/ - (fMatrix->getType() & SkMatrix::kPerspective_Mask)) { - // TODO !!!! -// this->drawText_asPaths(text, byteLength, x, y, paint); - return; - } - - SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); - SkAutoGlyphCache autoCache(paint, fMatrix); - SkGlyphCache* cache = autoCache.getCache(); - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); - - const char* stop = text + byteLength; - AlignProc alignProc = pick_align_proc(paint.getTextAlign()); - SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache); - TextMapState tms(*fMatrix, constY); - TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); - - if (paint.isSubpixelText()) { - // maybe we should skip the rounding if linearText is set - RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix); - - if (SkPaint::kLeft_Align == paint.getTextAlign()) { - while (text < stop) { - tmsProc(tms, pos); - - SkFixed fx = SkScalarToFixed(tms.fLoc.fX); - SkFixed fy = SkScalarToFixed(tms.fLoc.fY); - - if (kRound_Y_Baseline == roundBaseline) { - fy = (fy + 0x8000) & ~0xFFFF; - } else if (kRound_X_Baseline == roundBaseline) { - fx = (fx + 0x8000) & ~0xFFFF; - } - - const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy); - - if (glyph.fWidth) { - proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy)); - } - pos += scalarsPerPosition; - } - } else { - while (text < stop) { - const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0); - - if (glyph->fWidth) { - SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;) - SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;) - - SkFixed fx, fy; - tmsProc(tms, pos); - - { - SkIPoint fixedLoc; - alignProc(tms.fLoc, *glyph, &fixedLoc); - fx = fixedLoc.fX; - fy = fixedLoc.fY; - - if (kRound_Y_Baseline == roundBaseline) { - fy = (fy + 0x8000) & ~0xFFFF; - } else if (kRound_X_Baseline == roundBaseline) { - fx = (fx + 0x8000) & ~0xFFFF; - } - } - - // have to call again, now that we've been "aligned" - glyph = &glyphCacheProc(cache, &text, fx, fy); - // the assumption is that the advance hasn't changed - SkASSERT(prevAdvX == glyph->fAdvanceX); - SkASSERT(prevAdvY == glyph->fAdvanceY); - - proc(d1g, *glyph, SkFixedFloor(fx), SkFixedFloor(fy)); - } - pos += scalarsPerPosition; - } - } - } else { // not subpixel - while (text < stop) { - // the last 2 parameters are ignored - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); - - if (glyph.fWidth) { - tmsProc(tms, pos); - - SkIPoint fixedLoc; - alignProc(tms.fLoc, glyph, &fixedLoc); - - proc(d1g, glyph, - SkFixedRound(fixedLoc.fX), SkFixedRound(fixedLoc.fY)); - } - pos += scalarsPerPosition; - } - } -} - -#if defined _WIN32 && _MSC_VER >= 1300 -#pragma warning ( pop ) -#endif - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkPathMeasure.h" - -static void morphpoints(SkPoint dst[], const SkPoint src[], int count, - SkPathMeasure& meas, const SkMatrix& matrix) { - SkMatrix::MapXYProc proc = matrix.getMapXYProc(); - - for (int i = 0; i < count; i++) { - SkPoint pos; - SkVector tangent; - - proc(matrix, src[i].fX, src[i].fY, &pos); - SkScalar sx = pos.fX; - SkScalar sy = pos.fY; - - meas.getPosTan(sx, &pos, &tangent); - - /* This is the old way (that explains our approach but is way too slow - SkMatrix matrix; - SkPoint pt; - - pt.set(sx, sy); - matrix.setSinCos(tangent.fY, tangent.fX); - matrix.preTranslate(-sx, 0); - matrix.postTranslate(pos.fX, pos.fY); - matrix.mapPoints(&dst[i], &pt, 1); - */ - dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), - pos.fY + SkScalarMul(tangent.fX, sy)); - } -} - -/* TODO - - Need differentially more subdivisions when the follow-path is curvy. Not sure how to - determine that, but we need it. I guess a cheap answer is let the caller tell us, - but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. -*/ -static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, - const SkMatrix& matrix) { - SkPath::Iter iter(src, false); - SkPoint srcP[4], dstP[3]; - SkPath::Verb verb; - - while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { - switch (verb) { - case SkPath::kMove_Verb: - morphpoints(dstP, srcP, 1, meas, matrix); - dst->moveTo(dstP[0]); - break; - case SkPath::kLine_Verb: - // turn lines into quads to look bendy - srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); - srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); - morphpoints(dstP, srcP, 2, meas, matrix); - dst->quadTo(dstP[0], dstP[1]); - break; - case SkPath::kQuad_Verb: - morphpoints(dstP, &srcP[1], 2, meas, matrix); - dst->quadTo(dstP[0], dstP[1]); - break; - case SkPath::kCubic_Verb: - morphpoints(dstP, &srcP[1], 3, meas, matrix); - dst->cubicTo(dstP[0], dstP[1], dstP[2]); - break; - case SkPath::kClose_Verb: - dst->close(); - break; - default: - SkASSERT(!"unknown verb"); - break; - } - } -} - -void SkDraw::drawTextOnPath(const char text[], size_t byteLength, - const SkPath& follow, const SkMatrix* matrix, - const SkPaint& paint) const { - SkASSERT(byteLength == 0 || text != NULL); - - // nothing to draw - if (text == NULL || byteLength == 0 || - fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - SkTextToPathIter iter(text, byteLength, paint, true, true); - SkPathMeasure meas(follow, false); - SkScalar hOffset = 0; - - // need to measure first - if (paint.getTextAlign() != SkPaint::kLeft_Align) { - SkScalar pathLen = meas.getLength(); - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - pathLen = SkScalarHalf(pathLen); - } - hOffset += pathLen; - } - - const SkPath* iterPath; - SkScalar xpos; - SkMatrix scaledMatrix; - SkScalar scale = iter.getPathScale(); - - scaledMatrix.setScale(scale, scale); - - while ((iterPath = iter.next(&xpos)) != NULL) { - SkPath tmp; - SkMatrix m(scaledMatrix); - - m.postTranslate(xpos + hOffset, 0); - if (matrix) { - m.postConcat(*matrix); - } - morphpath(&tmp, *iterPath, meas, m); - this->drawPath(tmp, iter.getPaint()); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -struct VertState { - int f0, f1, f2; - - VertState(int vCount, const uint16_t indices[], int indexCount) - : fIndices(indices) { - fCurrIndex = 0; - if (indices) { - fCount = indexCount; - } else { - fCount = vCount; - } - } - - typedef bool (*Proc)(VertState*); - Proc chooseProc(SkCanvas::VertexMode mode); - -private: - int fCount; - int fCurrIndex; - const uint16_t* fIndices; - - static bool Triangles(VertState*); - static bool TrianglesX(VertState*); - static bool TriangleStrip(VertState*); - static bool TriangleStripX(VertState*); - static bool TriangleFan(VertState*); - static bool TriangleFanX(VertState*); -}; - -bool VertState::Triangles(VertState* state) { - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f0 = index + 0; - state->f1 = index + 1; - state->f2 = index + 2; - state->fCurrIndex = index + 3; - return true; -} - -bool VertState::TrianglesX(VertState* state) { - const uint16_t* indices = state->fIndices; - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f0 = indices[index + 0]; - state->f1 = indices[index + 1]; - state->f2 = indices[index + 2]; - state->fCurrIndex = index + 3; - return true; -} - -bool VertState::TriangleStrip(VertState* state) { - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f2 = index + 2; - if (index & 1) { - state->f0 = index + 1; - state->f1 = index + 0; - } else { - state->f0 = index + 0; - state->f1 = index + 1; - } - state->fCurrIndex = index + 1; - return true; -} - -bool VertState::TriangleStripX(VertState* state) { - const uint16_t* indices = state->fIndices; - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f2 = indices[index + 2]; - if (index & 1) { - state->f0 = indices[index + 1]; - state->f1 = indices[index + 0]; - } else { - state->f0 = indices[index + 0]; - state->f1 = indices[index + 1]; - } - state->fCurrIndex = index + 1; - return true; -} - -bool VertState::TriangleFan(VertState* state) { - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f0 = 0; - state->f1 = index + 1; - state->f2 = index + 2; - state->fCurrIndex = index + 1; - return true; -} - -bool VertState::TriangleFanX(VertState* state) { - const uint16_t* indices = state->fIndices; - int index = state->fCurrIndex; - if (index + 3 > state->fCount) { - return false; - } - state->f0 = indices[0]; - state->f1 = indices[index + 1]; - state->f2 = indices[index + 2]; - state->fCurrIndex = index + 1; - return true; -} - -VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { - switch (mode) { - case SkCanvas::kTriangles_VertexMode: - return fIndices ? TrianglesX : Triangles; - case SkCanvas::kTriangleStrip_VertexMode: - return fIndices ? TriangleStripX : TriangleStrip; - case SkCanvas::kTriangleFan_VertexMode: - return fIndices ? TriangleFanX : TriangleFan; - default: - return NULL; - } -} - -typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRegion*, - SkBlitter*); - -static HairProc ChooseHairProc(bool doAntiAlias) { - return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; -} - -static bool texture_to_matrix(const VertState& state, const SkPoint verts[], - const SkPoint texs[], SkMatrix* matrix) { - SkPoint src[3], dst[3]; - - src[0] = texs[state.f0]; - src[1] = texs[state.f1]; - src[2] = texs[state.f2]; - dst[0] = verts[state.f0]; - dst[1] = verts[state.f1]; - dst[2] = verts[state.f2]; - return matrix->setPolyToPoly(src, dst, 3); -} - -class SkTriColorShader : public SkShader { -public: - SkTriColorShader() {} - - bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); - - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count); - -protected: - SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {} - - virtual Factory getFactory() { return CreateProc; } - -private: - SkMatrix fDstToUnit; - SkPMColor fColors[3]; - - static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkTriColorShader, (buffer)); - } - typedef SkShader INHERITED; -}; - -bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], - int index0, int index1, int index2) { - - fColors[0] = SkPreMultiplyColor(colors[index0]); - fColors[1] = SkPreMultiplyColor(colors[index1]); - fColors[2] = SkPreMultiplyColor(colors[index2]); - - SkMatrix m, im; - m.reset(); - m.set(0, pts[index1].fX - pts[index0].fX); - m.set(1, pts[index2].fX - pts[index0].fX); - m.set(2, pts[index0].fX); - m.set(3, pts[index1].fY - pts[index0].fY); - m.set(4, pts[index2].fY - pts[index0].fY); - m.set(5, pts[index0].fY); - if (!m.invert(&im)) { - return false; - } - return fDstToUnit.setConcat(im, this->getTotalInverse()); -} - -#include "SkColorPriv.h" -#include "SkPorterDuff.h" -#include "SkComposeShader.h" -#include "SkXfermode.h" - -static int ScalarTo256(SkScalar v) { - int scale = SkScalarToFixed(v) >> 8; - if (scale < 0) { - scale = 0; - } - if (scale > 255) { - scale = 255; - } - return SkAlpha255To256(scale); -} - -void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { - SkPoint src; - - for (int i = 0; i < count; i++) { - fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); - x += 1; - - int scale1 = ScalarTo256(src.fX); - int scale2 = ScalarTo256(src.fY); - int scale0 = 256 - scale1 - scale2; - if (scale0 < 0) { - if (scale1 > scale2) { - scale2 = 256 - scale1; - } else { - scale1 = 256 - scale2; - } - scale0 = 0; - } - - dstC[i] = SkAlphaMulQ(fColors[0], scale0) + - SkAlphaMulQ(fColors[1], scale1) + - SkAlphaMulQ(fColors[2], scale2); - } -} - -void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, - const SkPoint vertices[], const SkPoint textures[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) const { - SkASSERT(0 == count || NULL != vertices); - - // abort early if there is nothing to draw - if (count < 3 || (indices && indexCount < 3) || fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { - return; - } - - // transform out vertices into device coordinates - SkAutoSTMalloc<16, SkPoint> storage(count); - SkPoint* devVerts = storage.get(); - fMatrix->mapPoints(devVerts, vertices, count); - - if (fBounder) { - SkRect bounds; - bounds.set(devVerts, count); - if (!fBounder->doRect(bounds, paint)) { - return; - } - } - - /* - We can draw the vertices in 1 of 4 ways: - - - solid color (no shader/texture[], no colors[]) - - just colors (no shader/texture[], has colors[]) - - just texture (has shader/texture[], no colors[]) - - colors * texture (has shader/texture[], has colors[]) - - Thus for texture drawing, we need both texture[] and a shader. - */ - - SkTriColorShader triShader; // must be above declaration of p - SkPaint p(paint); - - SkShader* shader = p.getShader(); - if (NULL == shader) { - // if we have no shader, we ignore the texture coordinates - textures = NULL; - } else if (NULL == textures) { - // if we don't have texture coordinates, ignore the shader - p.setShader(NULL); - shader = NULL; - } - - // setup the custom shader (if needed) - if (NULL != colors) { - if (NULL == textures) { - // just colors (no texture) - p.setShader(&triShader); - } else { - // colors * texture - SkASSERT(shader); - bool releaseMode = false; - if (NULL == xmode) { - xmode = SkPorterDuff::CreateXfermode( - SkPorterDuff::kMultiply_Mode); - releaseMode = true; - } - SkShader* compose = SkNEW_ARGS(SkComposeShader, - (&triShader, shader, xmode)); - p.setShader(compose)->unref(); - if (releaseMode) { - xmode->unref(); - } - } - } - - SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); - // setup our state and function pointer for iterating triangles - VertState state(count, indices, indexCount); - VertState::Proc vertProc = state.chooseProc(vmode); - - if (NULL != textures || NULL != colors) { - SkMatrix localM, tempM; - bool hasLocalM = shader && shader->getLocalMatrix(&localM); - - if (NULL != colors) { - if (!triShader.setContext(*fBitmap, p, *fMatrix)) { - colors = NULL; - } - } - - while (vertProc(&state)) { - if (NULL != textures) { - if (texture_to_matrix(state, vertices, textures, &tempM)) { - if (hasLocalM) { - tempM.postConcat(localM); - } - shader->setLocalMatrix(tempM); - // need to recal setContext since we changed the local matrix - if (!shader->setContext(*fBitmap, p, *fMatrix)) { - continue; - } - } - } - if (NULL != colors) { - if (!triShader.setup(vertices, colors, - state.f0, state.f1, state.f2)) { - continue; - } - } - SkScan::FillTriangle(devVerts[state.f0], devVerts[state.f1], - devVerts[state.f2], fClip, blitter.get()); - } - // now restore the shader's original local matrix - if (NULL != shader) { - if (hasLocalM) { - shader->setLocalMatrix(localM); - } else { - shader->resetLocalMatrix(); - } - } - } else { - // no colors[] and no texture - HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); - while (vertProc(&state)) { - hairProc(devVerts[state.f0], devVerts[state.f1], fClip, blitter.get()); - hairProc(devVerts[state.f1], devVerts[state.f2], fClip, blitter.get()); - hairProc(devVerts[state.f2], devVerts[state.f0], fClip, blitter.get()); - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - -void SkDraw::validate() const { - SkASSERT(fBitmap != NULL); - SkASSERT(fMatrix != NULL); - SkASSERT(fClip != NULL); - - const SkIRect& cr = fClip->getBounds(); - SkIRect br; - - br.set(0, 0, fBitmap->width(), fBitmap->height()); - SkASSERT(cr.isEmpty() || br.contains(cr)); -} - -#endif - -////////////////////////////////////////////////////////////////////////////////////////// - -bool SkBounder::doIRect(const SkIRect& r) { - SkIRect rr; - return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); -} - -bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, - const SkPaint& paint) { - SkIRect r; - SkScalar v0, v1; - - v0 = pt0.fX; - v1 = pt1.fX; - if (v0 > v1) { - SkTSwap<SkScalar>(v0, v1); - } - r.fLeft = SkScalarFloor(v0); - r.fRight = SkScalarCeil(v1); - - v0 = pt0.fY; - v1 = pt1.fY; - if (v0 > v1) { - SkTSwap<SkScalar>(v0, v1); - } - r.fTop = SkScalarFloor(v0); - r.fBottom = SkScalarCeil(v1); - - if (paint.isAntiAlias()) { - r.inset(-1, -1); - } - return this->doIRect(r); -} - -bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { - SkIRect r; - - if (paint.getStyle() == SkPaint::kFill_Style) { - rect.round(&r); - } else { - int rad = -1; - rect.roundOut(&r); - if (paint.isAntiAlias()) { - rad = -2; - } - r.inset(rad, rad); - } - return this->doIRect(r); -} - -bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { - SkRect bounds; - SkIRect r; - - path.computeBounds(&bounds, SkPath::kFast_BoundsType); - - if (doFill) { - bounds.round(&r); - } else { // hairline - bounds.roundOut(&r); - } - - if (paint.isAntiAlias()) { - r.inset(-1, -1); - } - return this->doIRect(r); -} - -void SkBounder::commit() { - // override in subclass -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkPath.h" -#include "SkDraw.h" -#include "SkRegion.h" -#include "SkBlitter.h" - -static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, - SkMaskFilter* filter, const SkMatrix* filterMatrix, - SkIRect* bounds) { - if (devPath.isEmpty()) { - return false; - } - - SkIPoint margin; - margin.set(0, 0); - - // init our bounds from the path - { - SkRect pathBounds; - devPath.computeBounds(&pathBounds, SkPath::kExact_BoundsType); - pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf); - pathBounds.roundOut(bounds); - } - - if (filter) { - SkASSERT(filterMatrix); - - SkMask srcM, dstM; - - srcM.fBounds = *bounds; - srcM.fFormat = SkMask::kA8_Format; - srcM.fImage = NULL; - if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { - return false; - } - *bounds = dstM.fBounds; - } - - if (clipBounds && !SkIRect::Intersects(*clipBounds, *bounds)) { - return false; - } - - // (possibly) trim the srcM bounds to reflect the clip - // (plus whatever slop the filter needs) - if (clipBounds && !clipBounds->contains(*bounds)) { - SkIRect tmp = *bounds; - (void)tmp.intersect(*clipBounds); - tmp.inset(-margin.fX, -margin.fY); - (void)bounds->intersect(tmp); - } - - return true; -} - -static void draw_into_mask(const SkMask& mask, const SkPath& devPath) { - SkBitmap bm; - SkDraw draw; - SkRegion clipRgn; - SkMatrix matrix; - SkPaint paint; - - bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); - bm.setPixels(mask.fImage); - - clipRgn.setRect(0, 0, mask.fBounds.width(), mask.fBounds.height()); - matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), - -SkIntToScalar(mask.fBounds.fTop)); - - draw.fBitmap = &bm; - draw.fClip = &clipRgn; - draw.fMatrix = &matrix; - draw.fBounder = NULL; - paint.setAntiAlias(true); - draw.drawPath(devPath, paint); -} - -bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, - SkMaskFilter* filter, const SkMatrix* filterMatrix, - SkMask* mask, SkMask::CreateMode mode) { - if (SkMask::kJustRenderImage_CreateMode != mode) { - if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) - return false; - } - - if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { - mask->fFormat = SkMask::kA8_Format; - mask->fRowBytes = mask->fBounds.width(); - mask->fImage = SkMask::AllocImage(mask->computeImageSize()); - memset(mask->fImage, 0, mask->computeImageSize()); - } - - if (SkMask::kJustComputeBounds_CreateMode != mode) { - draw_into_mask(*mask, devPath); - } - - return true; -} |