Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "SkArenaAlloc.h"
      8 #include "SkBlurDrawLooper.h"
      9 #include "SkBlurMaskFilter.h"
     10 #include "SkCanvas.h"
     11 #include "SkColorSpaceXformer.h"
     12 #include "SkColor.h"
     13 #include "SkMaskFilterBase.h"
     14 #include "SkReadBuffer.h"
     15 #include "SkWriteBuffer.h"
     16 #include "SkLayerDrawLooper.h"
     17 #include "SkString.h"
     18 #include "SkStringUtils.h"
     19 #include "SkUnPreMultiply.h"
     20 #include "SkXfermodePriv.h"
     21 
     22 SkLayerDrawLooper::LayerInfo::LayerInfo() {
     23     fPaintBits = 0;                     // ignore our paint fields
     24     fColorMode = SkBlendMode::kDst;     // ignore our color
     25     fOffset.set(0, 0);
     26     fPostTranslate = false;
     27 }
     28 
     29 SkLayerDrawLooper::SkLayerDrawLooper()
     30         : fRecs(nullptr),
     31           fCount(0) {
     32 }
     33 
     34 SkLayerDrawLooper::~SkLayerDrawLooper() {
     35     Rec* rec = fRecs;
     36     while (rec) {
     37         Rec* next = rec->fNext;
     38         delete rec;
     39         rec = next;
     40     }
     41 }
     42 
     43 SkLayerDrawLooper::Context*
     44 SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const {
     45     canvas->save();
     46     return alloc->make<LayerDrawLooperContext>(this);
     47 }
     48 
     49 static SkColor xferColor(SkColor src, SkColor dst, SkBlendMode mode) {
     50     switch (mode) {
     51         case SkBlendMode::kSrc:
     52             return src;
     53         case SkBlendMode::kDst:
     54             return dst;
     55         default: {
     56             SkPMColor pmS = SkPreMultiplyColor(src);
     57             SkPMColor pmD = SkPreMultiplyColor(dst);
     58             SkXfermode::Peek(mode)->xfer32(&pmD, &pmS, 1, nullptr);
     59             return SkUnPreMultiply::PMColorToColor(pmD);
     60         }
     61     }
     62 }
     63 
     64 // Even with kEntirePaint_Bits, we always ensure that the master paint's
     65 // text-encoding is respected, since that controls how we interpret the
     66 // text/length parameters of a draw[Pos]Text call.
     67 void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo(
     68         SkPaint* dst, const SkPaint& src, const LayerInfo& info) {
     69     SkColor srcColor = src.getColor();
     70 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     71     // The framework may respect the alpha value on the original paint.
     72     // Match this legacy behavior.
     73     if (SkColorGetA(srcColor) == 255) {
     74         srcColor = SkColorSetA(srcColor, dst->getAlpha());
     75     }
     76 #endif
     77     dst->setColor(xferColor(srcColor, dst->getColor(), (SkBlendMode)info.fColorMode));
     78 
     79     BitFlags bits = info.fPaintBits;
     80     SkPaint::TextEncoding encoding = dst->getTextEncoding();
     81 
     82     if (0 == bits) {
     83         return;
     84     }
     85     if (kEntirePaint_Bits == bits) {
     86         // we've already computed these, so save it from the assignment
     87         uint32_t f = dst->getFlags();
     88         SkColor c = dst->getColor();
     89         *dst = src;
     90         dst->setFlags(f);
     91         dst->setColor(c);
     92         dst->setTextEncoding(encoding);
     93         return;
     94     }
     95 
     96     if (bits & kStyle_Bit) {
     97         dst->setStyle(src.getStyle());
     98         dst->setStrokeWidth(src.getStrokeWidth());
     99         dst->setStrokeMiter(src.getStrokeMiter());
    100         dst->setStrokeCap(src.getStrokeCap());
    101         dst->setStrokeJoin(src.getStrokeJoin());
    102     }
    103 
    104     if (bits & kTextSkewX_Bit) {
    105         dst->setTextSkewX(src.getTextSkewX());
    106     }
    107 
    108     if (bits & kPathEffect_Bit) {
    109         dst->setPathEffect(src.refPathEffect());
    110     }
    111     if (bits & kMaskFilter_Bit) {
    112         dst->setMaskFilter(src.refMaskFilter());
    113     }
    114     if (bits & kShader_Bit) {
    115         dst->setShader(src.refShader());
    116     }
    117     if (bits & kColorFilter_Bit) {
    118         dst->setColorFilter(src.refColorFilter());
    119     }
    120     if (bits & kXfermode_Bit) {
    121         dst->setBlendMode(src.getBlendMode());
    122     }
    123 
    124     // we don't override these
    125 #if 0
    126     dst->setTypeface(src.getTypeface());
    127     dst->setTextSize(src.getTextSize());
    128     dst->setTextScaleX(src.getTextScaleX());
    129     dst->setRasterizer(src.getRasterizer());
    130     dst->setLooper(src.getLooper());
    131     dst->setTextEncoding(src.getTextEncoding());
    132     dst->setHinting(src.getHinting());
    133 #endif
    134 }
    135 
    136 // Should we add this to canvas?
    137 static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
    138     SkMatrix m = canvas->getTotalMatrix();
    139     m.postTranslate(dx, dy);
    140     canvas->setMatrix(m);
    141 }
    142 
    143 SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
    144         const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
    145 
    146 bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
    147                                                      SkPaint* paint) {
    148     canvas->restore();
    149     if (nullptr == fCurrRec) {
    150         return false;
    151     }
    152 
    153     ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
    154 
    155     canvas->save();
    156     if (fCurrRec->fInfo.fPostTranslate) {
    157         postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
    158                       fCurrRec->fInfo.fOffset.fY);
    159     } else {
    160         canvas->translate(fCurrRec->fInfo.fOffset.fX,
    161                           fCurrRec->fInfo.fOffset.fY);
    162     }
    163     fCurrRec = fCurrRec->fNext;
    164 
    165     return true;
    166 }
    167 
    168 bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
    169     if (fCount != 2) {
    170         return false;
    171     }
    172     const Rec* rec = fRecs;
    173 
    174     // bottom layer needs to be just blur(maskfilter)
    175     if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
    176         return false;
    177     }
    178     if (SkBlendMode::kSrc != (SkBlendMode)rec->fInfo.fColorMode) {
    179         return false;
    180     }
    181     const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
    182     if (nullptr == mf) {
    183         return false;
    184     }
    185     SkMaskFilterBase::BlurRec maskBlur;
    186     if (!as_MFB(mf)->asABlur(&maskBlur)) {
    187         return false;
    188     }
    189 
    190     rec = rec->fNext;
    191     // top layer needs to be "plain"
    192     if (rec->fInfo.fPaintBits) {
    193         return false;
    194     }
    195     if (SkBlendMode::kDst != (SkBlendMode)rec->fInfo.fColorMode) {
    196         return false;
    197     }
    198     if (!rec->fInfo.fOffset.equals(0, 0)) {
    199         return false;
    200     }
    201 
    202     if (bsRec) {
    203         bsRec->fSigma = maskBlur.fSigma;
    204         bsRec->fOffset = fRecs->fInfo.fOffset;
    205         bsRec->fColor = fRecs->fPaint.getColor();
    206         bsRec->fStyle = maskBlur.fStyle;
    207         bsRec->fQuality = maskBlur.fQuality;
    208     }
    209     return true;
    210 }
    211 
    212 sk_sp<SkDrawLooper> SkLayerDrawLooper::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    213     if (!fCount) {
    214         return sk_ref_sp(const_cast<SkLayerDrawLooper*>(this));
    215     }
    216 
    217     auto looper = sk_sp<SkLayerDrawLooper>(new SkLayerDrawLooper());
    218     looper->fCount = fCount;
    219 
    220     Rec* oldRec = fRecs;
    221     Rec* newTopRec = new Rec();
    222     newTopRec->fInfo = oldRec->fInfo;
    223     newTopRec->fPaint = xformer->apply(oldRec->fPaint);
    224     newTopRec->fNext = nullptr;
    225 
    226     Rec* prevNewRec = newTopRec;
    227     oldRec = oldRec->fNext;
    228     while (oldRec) {
    229         Rec* newRec = new Rec();
    230         newRec->fInfo = oldRec->fInfo;
    231         newRec->fPaint = xformer->apply(oldRec->fPaint);
    232         newRec->fNext = nullptr;
    233         prevNewRec->fNext = newRec;
    234 
    235         prevNewRec = newRec;
    236         oldRec = oldRec->fNext;
    237     }
    238 
    239     looper->fRecs = newTopRec;
    240     return std::move(looper);
    241 }
    242 
    243 ///////////////////////////////////////////////////////////////////////////////
    244 
    245 void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
    246     buffer.writeInt(fCount);
    247 
    248     Rec* rec = fRecs;
    249     for (int i = 0; i < fCount; i++) {
    250         // Legacy "flagsmask" field -- now ignored, remove when we bump version
    251         buffer.writeInt(0);
    252 
    253         buffer.writeInt(rec->fInfo.fPaintBits);
    254         buffer.writeInt((int)rec->fInfo.fColorMode);
    255         buffer.writePoint(rec->fInfo.fOffset);
    256         buffer.writeBool(rec->fInfo.fPostTranslate);
    257         buffer.writePaint(rec->fPaint);
    258         rec = rec->fNext;
    259     }
    260 }
    261 
    262 sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) {
    263     int count = buffer.readInt();
    264 
    265     Builder builder;
    266     for (int i = 0; i < count; i++) {
    267         LayerInfo info;
    268         // Legacy "flagsmask" field -- now ignored, remove when we bump version
    269         (void)buffer.readInt();
    270 
    271         info.fPaintBits = buffer.readInt();
    272         info.fColorMode = (SkBlendMode)buffer.readInt();
    273         buffer.readPoint(&info.fOffset);
    274         info.fPostTranslate = buffer.readBool();
    275         buffer.readPaint(builder.addLayerOnTop(info));
    276     }
    277     return builder.detach();
    278 }
    279 
    280 #ifndef SK_IGNORE_TO_STRING
    281 void SkLayerDrawLooper::toString(SkString* str) const {
    282     str->appendf("SkLayerDrawLooper (%d): ", fCount);
    283 
    284     Rec* rec = fRecs;
    285     for (int i = 0; i < fCount; i++) {
    286         str->appendf("%d: paintBits: (", i);
    287         if (0 == rec->fInfo.fPaintBits) {
    288             str->append("None");
    289         } else if (kEntirePaint_Bits == rec->fInfo.fPaintBits) {
    290             str->append("EntirePaint");
    291         } else {
    292             bool needSeparator = false;
    293             SkAddFlagToString(str, SkToBool(kStyle_Bit & rec->fInfo.fPaintBits), "Style",
    294                               &needSeparator);
    295             SkAddFlagToString(str, SkToBool(kTextSkewX_Bit & rec->fInfo.fPaintBits), "TextSkewX",
    296                               &needSeparator);
    297             SkAddFlagToString(str, SkToBool(kPathEffect_Bit & rec->fInfo.fPaintBits), "PathEffect",
    298                               &needSeparator);
    299             SkAddFlagToString(str, SkToBool(kMaskFilter_Bit & rec->fInfo.fPaintBits), "MaskFilter",
    300                               &needSeparator);
    301             SkAddFlagToString(str, SkToBool(kShader_Bit & rec->fInfo.fPaintBits), "Shader",
    302                               &needSeparator);
    303             SkAddFlagToString(str, SkToBool(kColorFilter_Bit & rec->fInfo.fPaintBits), "ColorFilter",
    304                               &needSeparator);
    305             SkAddFlagToString(str, SkToBool(kXfermode_Bit & rec->fInfo.fPaintBits), "Xfermode",
    306                               &needSeparator);
    307         }
    308         str->append(") ");
    309 
    310         static const char* gModeStrings[(int)SkBlendMode::kLastMode+1] = {
    311             "kClear", "kSrc", "kDst", "kSrcOver", "kDstOver", "kSrcIn", "kDstIn",
    312             "kSrcOut", "kDstOut", "kSrcATop", "kDstATop", "kXor", "kPlus",
    313             "kMultiply", "kScreen", "kOverlay", "kDarken", "kLighten", "kColorDodge",
    314             "kColorBurn", "kHardLight", "kSoftLight", "kDifference", "kExclusion"
    315         };
    316 
    317         str->appendf("mode: %s ", gModeStrings[(int)rec->fInfo.fColorMode]);
    318 
    319         str->append("offset: (");
    320         str->appendScalar(rec->fInfo.fOffset.fX);
    321         str->append(", ");
    322         str->appendScalar(rec->fInfo.fOffset.fY);
    323         str->append(") ");
    324 
    325         str->append("postTranslate: ");
    326         if (rec->fInfo.fPostTranslate) {
    327             str->append("true ");
    328         } else {
    329             str->append("false ");
    330         }
    331 
    332         rec->fPaint.toString(str);
    333         rec = rec->fNext;
    334     }
    335 }
    336 #endif
    337 
    338 SkLayerDrawLooper::Builder::Builder()
    339         : fRecs(nullptr),
    340           fTopRec(nullptr),
    341           fCount(0) {
    342 }
    343 
    344 SkLayerDrawLooper::Builder::~Builder() {
    345     Rec* rec = fRecs;
    346     while (rec) {
    347         Rec* next = rec->fNext;
    348         delete rec;
    349         rec = next;
    350     }
    351 }
    352 
    353 SkPaint* SkLayerDrawLooper::Builder::addLayer(const LayerInfo& info) {
    354     fCount += 1;
    355 
    356     Rec* rec = new Rec;
    357     rec->fNext = fRecs;
    358     rec->fInfo = info;
    359     fRecs = rec;
    360     if (nullptr == fTopRec) {
    361         fTopRec = rec;
    362     }
    363 
    364     return &rec->fPaint;
    365 }
    366 
    367 void SkLayerDrawLooper::Builder::addLayer(SkScalar dx, SkScalar dy) {
    368     LayerInfo info;
    369 
    370     info.fOffset.set(dx, dy);
    371     (void)this->addLayer(info);
    372 }
    373 
    374 SkPaint* SkLayerDrawLooper::Builder::addLayerOnTop(const LayerInfo& info) {
    375     fCount += 1;
    376 
    377     Rec* rec = new Rec;
    378     rec->fNext = nullptr;
    379     rec->fInfo = info;
    380     if (nullptr == fRecs) {
    381         fRecs = rec;
    382     } else {
    383         SkASSERT(fTopRec);
    384         fTopRec->fNext = rec;
    385     }
    386     fTopRec = rec;
    387 
    388     return &rec->fPaint;
    389 }
    390 
    391 sk_sp<SkDrawLooper> SkLayerDrawLooper::Builder::detach() {
    392     SkLayerDrawLooper* looper = new SkLayerDrawLooper;
    393     looper->fCount = fCount;
    394     looper->fRecs = fRecs;
    395 
    396     fCount = 0;
    397     fRecs = nullptr;
    398     fTopRec = nullptr;
    399 
    400     return sk_sp<SkDrawLooper>(looper);
    401 }
    402 
    403 sk_sp<SkDrawLooper> SkBlurDrawLooper::Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy)
    404 {
    405     sk_sp<SkMaskFilter> blur = nullptr;
    406     if (sigma > 0.0f) {
    407         blur = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, sigma, SkBlurMaskFilter::kNone_BlurFlag);
    408     }
    409 
    410     SkLayerDrawLooper::Builder builder;
    411 
    412     // First layer
    413     SkLayerDrawLooper::LayerInfo defaultLayer;
    414     builder.addLayer(defaultLayer);
    415 
    416     // Blur layer
    417     SkLayerDrawLooper::LayerInfo blurInfo;
    418     blurInfo.fColorMode = SkBlendMode::kSrc;
    419     blurInfo.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
    420     blurInfo.fOffset = SkVector::Make(dx, dy);
    421     SkPaint* paint = builder.addLayer(blurInfo);
    422     paint->setMaskFilter(std::move(blur));
    423     paint->setColor(color);
    424 
    425     return builder.detach();
    426 }
    427