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