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