michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. 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: #include "SkCanvas.h" michael@0: #include "SkColor.h" michael@0: #include "SkReadBuffer.h" michael@0: #include "SkWriteBuffer.h" michael@0: #include "SkLayerDrawLooper.h" michael@0: #include "SkString.h" michael@0: #include "SkStringUtils.h" michael@0: #include "SkUnPreMultiply.h" michael@0: michael@0: SkLayerDrawLooper::LayerInfo::LayerInfo() { michael@0: fPaintBits = 0; // ignore our paint fields michael@0: fColorMode = SkXfermode::kDst_Mode; // ignore our color michael@0: fOffset.set(0, 0); michael@0: fPostTranslate = false; michael@0: } michael@0: michael@0: SkLayerDrawLooper::SkLayerDrawLooper() michael@0: : fRecs(NULL), michael@0: fTopRec(NULL), michael@0: fCount(0) { michael@0: } michael@0: michael@0: SkLayerDrawLooper::~SkLayerDrawLooper() { michael@0: Rec* rec = fRecs; michael@0: while (rec) { michael@0: Rec* next = rec->fNext; michael@0: SkDELETE(rec); michael@0: rec = next; michael@0: } michael@0: } michael@0: michael@0: SkPaint* SkLayerDrawLooper::addLayer(const LayerInfo& info) { michael@0: fCount += 1; michael@0: michael@0: Rec* rec = SkNEW(Rec); michael@0: rec->fNext = fRecs; michael@0: rec->fInfo = info; michael@0: fRecs = rec; michael@0: if (NULL == fTopRec) { michael@0: fTopRec = rec; michael@0: } michael@0: michael@0: return &rec->fPaint; michael@0: } michael@0: michael@0: void SkLayerDrawLooper::addLayer(SkScalar dx, SkScalar dy) { michael@0: LayerInfo info; michael@0: michael@0: info.fOffset.set(dx, dy); michael@0: (void)this->addLayer(info); michael@0: } michael@0: michael@0: SkPaint* SkLayerDrawLooper::addLayerOnTop(const LayerInfo& info) { michael@0: fCount += 1; michael@0: michael@0: Rec* rec = SkNEW(Rec); michael@0: rec->fNext = NULL; michael@0: rec->fInfo = info; michael@0: if (NULL == fRecs) { michael@0: fRecs = rec; michael@0: } else { michael@0: SkASSERT(NULL != fTopRec); michael@0: fTopRec->fNext = rec; michael@0: } michael@0: fTopRec = rec; michael@0: michael@0: return &rec->fPaint; michael@0: } michael@0: michael@0: SkLayerDrawLooper::Context* SkLayerDrawLooper::createContext(SkCanvas* canvas, void* storage) const { michael@0: canvas->save(SkCanvas::kMatrix_SaveFlag); michael@0: return SkNEW_PLACEMENT_ARGS(storage, LayerDrawLooperContext, (this)); michael@0: } michael@0: michael@0: static SkColor xferColor(SkColor src, SkColor dst, SkXfermode::Mode mode) { michael@0: switch (mode) { michael@0: case SkXfermode::kSrc_Mode: michael@0: return src; michael@0: case SkXfermode::kDst_Mode: michael@0: return dst; michael@0: default: { michael@0: SkPMColor pmS = SkPreMultiplyColor(src); michael@0: SkPMColor pmD = SkPreMultiplyColor(dst); michael@0: SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD); michael@0: return SkUnPreMultiply::PMColorToColor(result); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Even with kEntirePaint_Bits, we always ensure that the master paint's michael@0: // text-encoding is respected, since that controls how we interpret the michael@0: // text/length parameters of a draw[Pos]Text call. michael@0: void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo( michael@0: SkPaint* dst, const SkPaint& src, const LayerInfo& info) { michael@0: michael@0: dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode)); michael@0: michael@0: BitFlags bits = info.fPaintBits; michael@0: SkPaint::TextEncoding encoding = dst->getTextEncoding(); michael@0: michael@0: if (0 == bits) { michael@0: return; michael@0: } michael@0: if (kEntirePaint_Bits == bits) { michael@0: // we've already computed these, so save it from the assignment michael@0: uint32_t f = dst->getFlags(); michael@0: SkColor c = dst->getColor(); michael@0: *dst = src; michael@0: dst->setFlags(f); michael@0: dst->setColor(c); michael@0: dst->setTextEncoding(encoding); michael@0: return; michael@0: } michael@0: michael@0: if (bits & kStyle_Bit) { michael@0: dst->setStyle(src.getStyle()); michael@0: dst->setStrokeWidth(src.getStrokeWidth()); michael@0: dst->setStrokeMiter(src.getStrokeMiter()); michael@0: dst->setStrokeCap(src.getStrokeCap()); michael@0: dst->setStrokeJoin(src.getStrokeJoin()); michael@0: } michael@0: michael@0: if (bits & kTextSkewX_Bit) { michael@0: dst->setTextSkewX(src.getTextSkewX()); michael@0: } michael@0: michael@0: if (bits & kPathEffect_Bit) { michael@0: dst->setPathEffect(src.getPathEffect()); michael@0: } michael@0: if (bits & kMaskFilter_Bit) { michael@0: dst->setMaskFilter(src.getMaskFilter()); michael@0: } michael@0: if (bits & kShader_Bit) { michael@0: dst->setShader(src.getShader()); michael@0: } michael@0: if (bits & kColorFilter_Bit) { michael@0: dst->setColorFilter(src.getColorFilter()); michael@0: } michael@0: if (bits & kXfermode_Bit) { michael@0: dst->setXfermode(src.getXfermode()); michael@0: } michael@0: michael@0: // we don't override these michael@0: #if 0 michael@0: dst->setTypeface(src.getTypeface()); michael@0: dst->setTextSize(src.getTextSize()); michael@0: dst->setTextScaleX(src.getTextScaleX()); michael@0: dst->setRasterizer(src.getRasterizer()); michael@0: dst->setLooper(src.getLooper()); michael@0: dst->setTextEncoding(src.getTextEncoding()); michael@0: dst->setHinting(src.getHinting()); michael@0: #endif michael@0: } michael@0: michael@0: // Should we add this to canvas? michael@0: static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) { michael@0: SkMatrix m = canvas->getTotalMatrix(); michael@0: m.postTranslate(dx, dy); michael@0: canvas->setMatrix(m); michael@0: } michael@0: michael@0: SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext( michael@0: const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {} michael@0: michael@0: bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas, michael@0: SkPaint* paint) { michael@0: canvas->restore(); michael@0: if (NULL == fCurrRec) { michael@0: return false; michael@0: } michael@0: michael@0: ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo); michael@0: michael@0: canvas->save(SkCanvas::kMatrix_SaveFlag); michael@0: if (fCurrRec->fInfo.fPostTranslate) { michael@0: postTranslate(canvas, fCurrRec->fInfo.fOffset.fX, michael@0: fCurrRec->fInfo.fOffset.fY); michael@0: } else { michael@0: canvas->translate(fCurrRec->fInfo.fOffset.fX, michael@0: fCurrRec->fInfo.fOffset.fY); michael@0: } michael@0: fCurrRec = fCurrRec->fNext; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: michael@0: #ifdef SK_DEBUG michael@0: { michael@0: Rec* rec = fRecs; michael@0: int count = 0; michael@0: while (rec) { michael@0: rec = rec->fNext; michael@0: count += 1; michael@0: } michael@0: SkASSERT(count == fCount); michael@0: } michael@0: #endif michael@0: michael@0: buffer.writeInt(fCount); michael@0: michael@0: Rec* rec = fRecs; michael@0: for (int i = 0; i < fCount; i++) { michael@0: // Legacy "flagsmask" field -- now ignored, remove when we bump version michael@0: buffer.writeInt(0); michael@0: michael@0: buffer.writeInt(rec->fInfo.fPaintBits); michael@0: buffer.writeInt(rec->fInfo.fColorMode); michael@0: buffer.writePoint(rec->fInfo.fOffset); michael@0: buffer.writeBool(rec->fInfo.fPostTranslate); michael@0: buffer.writePaint(rec->fPaint); michael@0: rec = rec->fNext; michael@0: } michael@0: } michael@0: michael@0: SkFlattenable* SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) { michael@0: int count = buffer.readInt(); michael@0: michael@0: Builder builder; michael@0: for (int i = 0; i < count; i++) { michael@0: LayerInfo info; michael@0: // Legacy "flagsmask" field -- now ignored, remove when we bump version michael@0: (void)buffer.readInt(); michael@0: michael@0: info.fPaintBits = buffer.readInt(); michael@0: info.fColorMode = (SkXfermode::Mode)buffer.readInt(); michael@0: buffer.readPoint(&info.fOffset); michael@0: info.fPostTranslate = buffer.readBool(); michael@0: buffer.readPaint(builder.addLayerOnTop(info)); michael@0: } michael@0: SkLayerDrawLooper* looper = builder.detachLooper(); michael@0: SkASSERT(count == looper->fCount); michael@0: michael@0: #ifdef SK_DEBUG michael@0: { michael@0: Rec* rec = looper->fRecs; michael@0: int n = 0; michael@0: while (rec) { michael@0: rec = rec->fNext; michael@0: n += 1; michael@0: } michael@0: SkASSERT(count == n); michael@0: } michael@0: #endif michael@0: michael@0: return looper; michael@0: } michael@0: michael@0: #ifndef SK_IGNORE_TO_STRING michael@0: void SkLayerDrawLooper::toString(SkString* str) const { michael@0: str->appendf("SkLayerDrawLooper (%d): ", fCount); michael@0: michael@0: Rec* rec = fRecs; michael@0: for (int i = 0; i < fCount; i++) { michael@0: str->appendf("%d: paintBits: (", i); michael@0: if (0 == rec->fInfo.fPaintBits) { michael@0: str->append("None"); michael@0: } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) { michael@0: str->append("EntirePaint"); michael@0: } else { michael@0: bool needSeparator = false; michael@0: SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter", michael@0: &needSeparator); michael@0: SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode", michael@0: &needSeparator); michael@0: } michael@0: str->append(") "); michael@0: michael@0: static const char* gModeStrings[SkXfermode::kLastMode+1] = { michael@0: "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn", michael@0: "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus", michael@0: "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge", michael@0: "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion" michael@0: }; michael@0: michael@0: str->appendf("mode: %s ", gModeStrings[rec->fInfo.fColorMode]); michael@0: michael@0: str->append("offset: ("); michael@0: str->appendScalar(rec->fInfo.fOffset.fX); michael@0: str->append(", "); michael@0: str->appendScalar(rec->fInfo.fOffset.fY); michael@0: str->append(") "); michael@0: michael@0: str->append("postTranslate: "); michael@0: if (rec->fInfo.fPostTranslate) { michael@0: str->append("true "); michael@0: } else { michael@0: str->append("false "); michael@0: } michael@0: michael@0: rec->fPaint.toString(str); michael@0: rec = rec->fNext; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: SkLayerDrawLooper::Builder::Builder() michael@0: : fRecs(NULL), michael@0: fTopRec(NULL), michael@0: fCount(0) { michael@0: } michael@0: michael@0: SkLayerDrawLooper::Builder::~Builder() { michael@0: Rec* rec = fRecs; michael@0: while (rec) { michael@0: Rec* next = rec->fNext; michael@0: SkDELETE(rec); michael@0: rec = next; michael@0: } michael@0: } michael@0: michael@0: SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) { michael@0: fCount += 1; michael@0: michael@0: Rec* rec = SkNEW(Rec); michael@0: rec->fNext = fRecs; michael@0: rec->fInfo = info; michael@0: fRecs = rec; michael@0: if (NULL == fTopRec) { michael@0: fTopRec = rec; michael@0: } michael@0: michael@0: return &rec->fPaint; michael@0: } michael@0: michael@0: void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) { michael@0: LayerInfo info; michael@0: michael@0: info.fOffset.set(dx, dy); michael@0: (void)this->addLayer(info); michael@0: } michael@0: michael@0: SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) { michael@0: fCount += 1; michael@0: michael@0: Rec* rec = SkNEW(Rec); michael@0: rec->fNext = NULL; michael@0: rec->fInfo = info; michael@0: if (NULL == fRecs) { michael@0: fRecs = rec; michael@0: } else { michael@0: SkASSERT(NULL != fTopRec); michael@0: fTopRec->fNext = rec; michael@0: } michael@0: fTopRec = rec; michael@0: michael@0: return &rec->fPaint; michael@0: } michael@0: michael@0: SkLayerDrawLooper* SkLayerDrawLooper::Builder::detachLooper() { michael@0: SkLayerDrawLooper* looper = SkNEW(SkLayerDrawLooper); michael@0: looper->fCount = fCount; michael@0: looper->fRecs = fRecs; michael@0: michael@0: fCount = 0; michael@0: fRecs = NULL; michael@0: fTopRec = NULL; michael@0: michael@0: return looper; michael@0: }