blob: 3fafaf00e327ddb16380cfead65e053ca58e3980 [file] [log] [blame]
/*
* 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 "include/core/SkTypes.h"
#ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkMaskFilter.h"
#include "include/core/SkString.h"
#include "include/core/SkUnPreMultiply.h"
#include "include/effects/SkBlurDrawLooper.h"
#include "include/effects/SkLayerDrawLooper.h"
#include "src/base/SkArenaAlloc.h"
#include "src/core/SkBlendModePriv.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkStringUtils.h"
#include "src/core/SkWriteBuffer.h"
#include "src/core/SkXfermodePriv.h"
SkLayerDrawLooper::LayerInfo::LayerInfo() {
fPaintBits = 0; // ignore our paint fields
fColorMode = SkBlendMode::kDst; // ignore our color
fOffset.set(0, 0);
fPostTranslate = false;
}
SkLayerDrawLooper::SkLayerDrawLooper()
: fRecs(nullptr),
fCount(0) {
}
SkLayerDrawLooper::~SkLayerDrawLooper() {
Rec* rec = fRecs;
while (rec) {
Rec* next = rec->fNext;
delete rec;
rec = next;
}
}
SkLayerDrawLooper::Context*
SkLayerDrawLooper::makeContext(SkArenaAlloc* alloc) const {
return alloc->make<LayerDrawLooperContext>(this);
}
static SkColor4f xferColor(const SkColor4f& src, const SkColor4f& dst, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kSrc:
return src;
case SkBlendMode::kDst:
return dst;
default: {
SkPMColor4f pmS = src.premul();
SkPMColor4f pmD = dst.premul();
return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
}
}
}
// Even with kEntirePaint_Bits, we always ensure that the base 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) {
SkColor4f srcColor = src.getColor4f();
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
// The framework may respect the alpha value on the original paint.
// Match this legacy behavior.
if (src.getAlpha() == 255) {
srcColor.fA = dst->getColor4f().fA;
}
#endif
dst->setColor4f(xferColor(srcColor, dst->getColor4f(), (SkBlendMode)info.fColorMode),
sk_srgb_singleton());
BitFlags bits = info.fPaintBits;
if (0 == bits) {
return;
}
if (kEntirePaint_Bits == bits) {
// we've already computed these, so save it from the assignment
bool aa = dst->isAntiAlias();
bool di = dst->isDither();
SkColor4f c = dst->getColor4f();
*dst = src;
dst->setAntiAlias(aa);
dst->setDither(di);
dst->setColor4f(c, sk_srgb_singleton());
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 & kPathEffect_Bit) {
dst->setPathEffect(src.refPathEffect());
}
if (bits & kMaskFilter_Bit) {
dst->setMaskFilter(src.refMaskFilter());
}
if (bits & kShader_Bit) {
dst->setShader(src.refShader());
}
if (bits & kColorFilter_Bit) {
dst->setColorFilter(src.refColorFilter());
}
if (bits & kXfermode_Bit) {
dst->setBlender(src.refBlender());
}
// 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
}
SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
bool SkLayerDrawLooper::LayerDrawLooperContext::next(Info* info, SkPaint* paint) {
if (nullptr == fCurrRec) {
return false;
}
ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
if (info) {
info->fTranslate = fCurrRec->fInfo.fOffset;
info->fApplyPostCTM = fCurrRec->fInfo.fPostTranslate;
}
fCurrRec = fCurrRec->fNext;
return true;
}
bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
if (fCount != 2) {
return false;
}
const Rec* rec = fRecs;
// bottom layer needs to be just blur(maskfilter)
if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
return false;
}
if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
return false;
}
const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
if (nullptr == mf) {
return false;
}
SkMaskFilterBase::BlurRec maskBlur;
if (!as_MFB(mf)->asABlur(&maskBlur)) {
return false;
}
rec = rec->fNext;
// top layer needs to be "plain"
if (rec->fInfo.fPaintBits) {
return false;
}
if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
return false;
}
if (!rec->fInfo.fOffset.equals(0, 0)) {
return false;
}
if (bsRec) {
bsRec->fSigma = maskBlur.fSigma;
bsRec->fOffset = fRecs->fInfo.fOffset;
// TODO: Update BlurShadowRec to use SkColor4f?
bsRec->fColor = fRecs->fPaint.getColor();
bsRec->fStyle = maskBlur.fStyle;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
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((int)rec->fInfo.fColorMode);
buffer.writePoint(rec->fInfo.fOffset);
buffer.writeBool(rec->fInfo.fPostTranslate);
buffer.writePaint(rec->fPaint);
rec = rec->fNext;
}
}
sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
int count = buffer.readInt();
#if defined(SK_BUILD_FOR_FUZZER)
if (count > 100) {
count = 100;
}
#endif
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 = (SkBlendMode)buffer.readInt();
buffer.readPoint(&info.fOffset);
info.fPostTranslate = buffer.readBool();
*builder.addLayerOnTop(info) = buffer.readPaint();
if (!buffer.isValid()) {
return nullptr;
}
}
return builder.detach();
}
SkLayerDrawLooper::Builder::Builder()
: fRecs(nullptr),
fTopRec(nullptr),
fCount(0) {
}
SkLayerDrawLooper::Builder::~Builder() {
Rec* rec = fRecs;
while (rec) {
Rec* next = rec->fNext;
delete rec;
rec = next;
}
}
SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
fCount += 1;
Rec* rec = new Rec;
rec->fNext = fRecs;
rec->fInfo = info;
fRecs = rec;
if (nullptr == 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 = new Rec;
rec->fNext = nullptr;
rec->fInfo = info;
if (nullptr == fRecs) {
fRecs = rec;
} else {
SkASSERT(fTopRec);
fTopRec->fNext = rec;
}
fTopRec = rec;
return &rec->fPaint;
}
sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
SkLayerDrawLooper* looper = new SkLayerDrawLooper;
looper->fCount = fCount;
looper->fRecs = fRecs;
fCount = 0;
fRecs = nullptr;
fTopRec = nullptr;
return sk_sp<SkDrawLooper>(looper);
}
sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
{
return Make(SkColor4f::FromColor(color), sk_srgb_singleton(), sigma, dx, dy);
}
sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor4f color, SkColorSpace* cs,
SkScalar sigma, SkScalar dx, SkScalar dy)
{
sk_sp<SkMaskFilter> blur = nullptr;
if (sigma > 0.0f) {
blur = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, true);
}
SkLayerDrawLooper::Builder builder;
// First layer
SkLayerDrawLooper::LayerInfo defaultLayer;
builder.addLayer(defaultLayer);
// Blur layer
SkLayerDrawLooper::LayerInfo blurInfo;
blurInfo.fColorMode = SkBlendMode::kSrc;
blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
blurInfo.fOffset = SkVector::Make(dx, dy);
SkPaint* paint = builder.addLayer(blurInfo);
paint->setMaskFilter(std::move(blur));
paint->setColor4f(color, cs);
return builder.detach();
}
#endif