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