/** Create a new lighting shader that use the provided normal map, light and ambient color to light the diffuse bitmap. @param diffuse the diffuse bitmap @param normal the normal map @param light the light applied to the normal map @param ambient the linear (unpremul) ambient light color */ SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal, const SkLightingShader::Light& light, const SkColor ambient) : fDiffuseMap(diffuse) , fNormalMap(normal) , fLight(light) , fAmbientColor(ambient) { if (!fLight.fDirection.normalize()) { fLight.fDirection = SkPoint3::Make(0.0f, 0.0f, 1.0f); } SkColorSetA(fLight.fColor, 0xFF); SkColorSetA(fAmbientColor, 0xFF); }
// only call from constructor void SkBlurDrawLooper::initEffects() { SkASSERT(fBlurFlags <= kAll_BlurFlag); if (fSigma > 0) { uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ? SkBlurMaskFilter::kIgnoreTransform_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; flags |= fBlurFlags & kHighQuality_BlurFlag ? SkBlurMaskFilter::kHighQuality_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags); } else { fBlur = nullptr; } if (fBlurFlags & kOverrideColor_BlurFlag) { // Set alpha to 1 for the override since transparency will already // be baked into the blurred mask. SkColor opaqueColor = SkColorSetA(fBlurColor, 255); //The SrcIn xfer mode will multiply 'color' by the incoming alpha fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode); } else { fColorFilter = nullptr; } }
// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementHrefAttribute void SkSVGLinearGradient::collectColorStops(const SkSVGRenderContext& ctx, SkSTArray<2, SkScalar, true>* pos, SkSTArray<2, SkColor, true>* colors) const { // Used to resolve percentage offsets. const SkSVGLengthContext ltx(SkSize::Make(1, 1)); for (const auto& child : fChildren) { if (child->tag() != SkSVGTag::kStop) { continue; } const auto& stop = static_cast<const SkSVGStop&>(*child); colors->push_back(SkColorSetA(stop.stopColor(), SkScalarRoundToInt(stop.stopOpacity() * 255))); pos->push_back(SkTPin(ltx.resolve(stop.offset(), SkSVGLengthContext::LengthType::kOther), 0.f, 1.f)); } SkASSERT(colors->count() == pos->count()); if (pos->empty() && !fHref.value().isEmpty()) { const auto* ref = ctx.findNodeById(fHref); if (ref && ref->tag() == SkSVGTag::kLinearGradient) { static_cast<const SkSVGLinearGradient*>(ref)->collectColorStops(ctx, pos, colors); } } }
// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer // and restore static void apply_0(SkDebugCanvas* canvas, int curCommand) { SkSaveLayerCommand* saveLayer = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); const SkPaint* saveLayerPaint = saveLayer->paint(); // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed if (NULL != saveLayerPaint) { SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1); SkPaint* dbmrPaint = dbmr->paint(); if (NULL == dbmrPaint) { // if the DBMR doesn't have a paint just use the saveLayer's dbmr->setPaint(*saveLayerPaint); } else if (NULL != saveLayerPaint) { // Both paints are present so their alphas need to be combined SkColor color = saveLayerPaint->getColor(); int a0 = SkColorGetA(color); color = dbmrPaint->getColor(); int a1 = SkColorGetA(color); int newA = SkMulDiv255Round(a0, a1); SkASSERT(newA <= 0xFF); SkColor newColor = SkColorSetA(color, newA); dbmrPaint->setColor(newColor); } } canvas->deleteDrawCommandAt(curCommand+2); // restore canvas->deleteDrawCommandAt(curCommand); // saveLayer }
SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags) : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) { SkASSERT(flags <= kAll_BlurFlag); if (radius > 0) { uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ? SkBlurMaskFilter::kIgnoreTransform_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; blurFlags |= flags & kHighQuality_BlurFlag ? SkBlurMaskFilter::kHighQuality_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; fBlur = SkBlurMaskFilter::Create(radius, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags); } else { fBlur = NULL; } if (flags & kOverrideColor_BlurFlag) { // Set alpha to 1 for the override since transparency will already // be baked into the blurred mask. SkColor opaqueColor = SkColorSetA(color, 255); //The SrcIn xfer mode will multiply 'color' by the incoming alpha fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode); } else { fColorFilter = NULL; } }
DEF_TEST(ColorFilter, reporter) { SkRandom rand; for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { SkColor color = rand.nextU(); // ensure we always get a filter, by avoiding the possibility of a // special case that would return NULL (if color's alpha is 0 or 0xFF) color = SkColorSetA(color, 0x7F); SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, (SkXfermode::Mode)mode); // allow for no filter if we're in Dst mode (its a no op) if (SkXfermode::kDst_Mode == mode && NULL == cf) { continue; } SkAutoUnref aur(cf); REPORTER_ASSERT(reporter, cf); SkColor c = ~color; SkXfermode::Mode m = ILLEGAL_MODE; SkColor expectedColor = color; SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode; // SkDebugf("--- mc [%d %x] ", mode, color); REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m)); // handle special-case folding by the factory if (SkXfermode::kClear_Mode == mode) { if (c != expectedColor) { expectedColor = 0; } if (m != expectedMode) { expectedMode = SkXfermode::kSrc_Mode; } } // SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor); REPORTER_ASSERT(reporter, c == expectedColor); REPORTER_ASSERT(reporter, m == expectedMode); { SkColorFilter* cf2 = reincarnate_colorfilter(cf); SkAutoUnref aur2(cf2); REPORTER_ASSERT(reporter, cf2); SkColor c2 = ~color; SkXfermode::Mode m2 = ILLEGAL_MODE; REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2)); REPORTER_ASSERT(reporter, c2 == expectedColor); REPORTER_ASSERT(reporter, m2 == expectedMode); } } test_composecolorfilter_limit(reporter); }
static SkPDFIndirectReference make_alpha_function_shader(SkPDFDocument* doc, const SkPDFGradientShader::Key& state) { SkASSERT(state.fType != SkShader::kNone_GradientType); SkPDFGradientShader::Key opaqueState = clone_key(state); for (int i = 0; i < opaqueState.fInfo.fColorCount; i++) { opaqueState.fInfo.fColors[i] = SkColorSetA(opaqueState.fInfo.fColors[i], SK_AlphaOPAQUE); } opaqueState.fHash = hash(opaqueState); SkASSERT(!gradient_has_alpha(opaqueState)); SkRect bbox = SkRect::Make(state.fBBox); SkPDFIndirectReference colorShader = find_pdf_shader(doc, std::move(opaqueState), false); if (!colorShader) { return SkPDFIndirectReference(); } // Create resource dict with alpha graphics state as G0 and // pattern shader as P0, then write content stream. SkPDFIndirectReference alphaGsRef = create_smask_graphic_state(doc, state); std::unique_ptr<SkPDFDict> resourceDict = get_gradient_resource_dict(colorShader, alphaGsRef); std::unique_ptr<SkStreamAsset> colorStream = create_pattern_fill_content(alphaGsRef.fValue, colorShader.fValue, bbox); std::unique_ptr<SkPDFDict> alphaFunctionShader = SkPDFMakeDict(); SkPDFUtils::PopulateTilingPatternDict(alphaFunctionShader.get(), bbox, std::move(resourceDict), SkMatrix::I()); return SkPDFStreamOut(std::move(alphaFunctionShader), std::move(colorStream), doc); }
void SkBaseDevice::drawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint& paint) { SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; SkColor c; bool isFixedColor = false; const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType); while (iter.next(&srcR, &dstR, &isFixedColor, &c)) { if (isFixedColor || (srcR.width() <= 1.0f && srcR.height() <= 1.0f && image->readPixels(info, &c, 4, srcR.fLeft, srcR.fTop))) { // Fast draw with drawRect, if this is a patch containing a single color // or if this is a patch containing a single pixel. if (0 != c || !paint.isSrcOver()) { SkPaint paintCopy(paint); int alpha = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha())); paintCopy.setColor(SkColorSetA(c, alpha)); this->drawRect(dstR, paintCopy); } } else { this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); } } }
HighContrastFilterGM() { SkColor g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) }; SkColor g2Colors[] = { kColor2, SkColorSetA(kColor2, 0x20) }; SkPoint g1Points[] = { { 0, 0 }, { 0, 100 } }; SkPoint g2Points[] = { { 0, 0 }, { kSize, 0 } }; SkScalar pos[] = { 0.2f, 1.0f }; SkHighContrastConfig fConfig; fFilter = SkHighContrastFilter::Make(fConfig); fGr1 = SkGradientShader::MakeLinear( g1Points, g1Colors, pos, SK_ARRAY_COUNT(g1Colors), SkTileMode::kClamp); fGr2 = SkGradientShader::MakeLinear( g2Points, g2Colors, pos, SK_ARRAY_COUNT(g2Colors), SkTileMode::kClamp); }
static void draw_scene(SkCanvas* canvas, SkXfermode* mode, bool aa, SkShader* s1, SkShader* s2) { SkPaint paint; paint.setAntiAlias(aa); SkRect r, c, bounds = SkRect::MakeWH(kSize, kSize); c = bounds; c.fRight = bounds.centerX(); canvas->drawRect(bounds, paint); canvas->saveLayer(&bounds, NULL); r = bounds; r.inset(kInset, 0); paint.setShader(s1); paint.setColor(s1 ? SK_ColorBLACK : SkColorSetA(kColor1, 0x80)); canvas->drawOval(r, paint); if (!s1) { canvas->save(); canvas->clipRect(c); paint.setColor(s1 ? SK_ColorBLACK : kColor1); canvas->drawOval(r, paint); canvas->restore(); } SkPaint xferPaint; xferPaint.setXfermode(mode); canvas->saveLayer(&bounds, &xferPaint); r = bounds; r.inset(0, kInset); paint.setShader(s2); paint.setColor(s2 ? SK_ColorBLACK : SkColorSetA(kColor2, 0x80)); canvas->drawOval(r, paint); if (!s2) { canvas->save(); canvas->clipRect(c); paint.setColor(s2 ? SK_ColorBLACK : kColor2); canvas->drawOval(r, paint); canvas->restore(); } canvas->restore(); canvas->restore(); }
bool SkColorShader::asNewEffect(GrContext* context, const SkPaint& paint, const SkMatrix* localMatrix, GrColor* grColor, GrEffectRef** grEffect) const { *grEffect = NULL; SkColor skColor = fColor; U8CPU newA = SkMulDiv255Round(SkColorGetA(fColor), paint.getAlpha()); *grColor = SkColor2GrColor(SkColorSetA(skColor, newA)); return true; }
/** * Create a copy of this gradient state with alpha set to fully opaque * Only valid for gradient states. */ SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { SkASSERT(fType != SkShader::kNone_GradientType); SkPDFShader::State* newState = new SkPDFShader::State(*this); for (int i = 0; i < fInfo.fColorCount; i++) { newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], SK_AlphaOPAQUE); } return newState; }
bool SkShader::asLuminanceColor(SkColor* colorPtr) const { SkColor storage; if (nullptr == colorPtr) { colorPtr = &storage; } if (this->onAsLuminanceColor(colorPtr)) { *colorPtr = SkColorSetA(*colorPtr, 0xFF); // we only return opaque return true; } return false; }
static bool bitmapIsAllZero(const SkBitmap& bitmap) { bitmap.lockPixels(); bool result = true; for (int x = 0; result && x < bitmap.width(); ++x) { for (int y = 0; result && y < bitmap.height(); ++y) { if (SkColorSetA(bitmap.getColor(x, y), 0) != SK_ColorTRANSPARENT) result = false; } } bitmap.unlockPixels(); return result; }
virtual void recordCanvas(SkCanvas* canvas) { const SkPoint translateDelta = getTranslateDelta(); for (int i = 0; i < M; i++) { SkColor color = SK_ColorYELLOW + (i % 255); SkIRect rect = SkIRect::MakeWH(i,i); canvas->save(); // set the clip to the given region SkRegion region; region.setRect(rect); canvas->clipRegion(region); // fill the clip with a color SkPaint paint; paint.setColor(color); canvas->drawPaint(paint); // set a matrix on the canvas SkMatrix matrix; matrix.setRotate(SkIntToScalar(i % 360)); canvas->setMatrix(matrix); // create a simple bitmap SkBitmap bitmap; bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10); bitmap.allocPixels(); // draw a single color into the bitmap SkCanvas bitmapCanvas(bitmap); bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); // draw the bitmap onto the canvas canvas->drawBitmapMatrix(bitmap, matrix); canvas->restore(); canvas->translate(translateDelta.fX, translateDelta.fY); } }
bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas, SkPaint* paint) { switch (fState) { case kBeforeEdge: // we do nothing if a maskfilter is already installed if (paint->getMaskFilter()) { fState = kDone; return false; } #ifdef SK_BUILD_FOR_ANDROID SkColor blurColor; blurColor = fLooper->fBlurColor; if (SkColorGetA(blurColor) == 255) { blurColor = SkColorSetA(blurColor, paint->getAlpha()); } paint->setColor(blurColor); #else paint->setColor(fLooper->fBlurColor); #endif paint->setMaskFilter(fLooper->fBlur); paint->setColorFilter(fLooper->fColorFilter); canvas->save(); if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) { SkMatrix transform(canvas->getTotalMatrix()); transform.postTranslate(fLooper->fDx, fLooper->fDy); canvas->setMatrix(transform); } else { canvas->translate(fLooper->fDx, fLooper->fDy); } fState = kAfterEdge; return true; case kAfterEdge: canvas->restore(); fState = kDone; return true; default: SkASSERT(kDone == fState); return false; } }
// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer // and restore static void apply_1(SkDebugCanvas* canvas, int curCommand) { SkSaveLayerCommand* saveLayer = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand); const SkPaint* saveLayerPaint = saveLayer->paint(); // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed if (NULL != saveLayerPaint) { SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3); SkPaint* dbmrPaint = dbmr->paint(); if (NULL == dbmrPaint) { dbmr->setPaint(*saveLayerPaint); } else { SkColor newColor = SkColorSetA(dbmrPaint->getColor(), SkColorGetA(saveLayerPaint->getColor())); dbmrPaint->setColor(newColor); } } canvas->deleteDrawCommandAt(curCommand+5); // restore canvas->deleteDrawCommandAt(curCommand); // saveLayer }
void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags) { fDx = dx; fDy = dy; fBlurColor = color; fBlurFlags = flags; fState = kDone; SkASSERT(flags <= kAll_BlurFlag); if (sigma > 0) { uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ? SkBlurMaskFilter::kIgnoreTransform_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; blurFlags |= flags & kHighQuality_BlurFlag ? SkBlurMaskFilter::kHighQuality_BlurFlag : SkBlurMaskFilter::kNone_BlurFlag; fBlur = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle, sigma, blurFlags); } else { fBlur = NULL; } if (flags & kOverrideColor_BlurFlag) { // Set alpha to 1 for the override since transparency will already // be baked into the blurred mask. SkColor opaqueColor = SkColorSetA(color, 255); //The SrcIn xfer mode will multiply 'color' by the incoming alpha fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode); } else { fColorFilter = NULL; } }
static SkColor multiplyAlpha(SkColor color, float alpha) { return SkColorSetA(color, alpha * SkColorGetA(color)); }
void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) { SkASSERT(paint.getPathEffect() == NULL); NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); SkPaint newPaint = paint; // PDF treats a shader as a color, so we only set one or the other. SkRefPtr<SkPDFShader> pdfShader; const SkShader* shader = newPaint.getShader(); if (shader) { // PDF positions patterns relative to the initial transform, so // we need to apply the current transform to the shader parameters. SkMatrix transform = fGraphicStack[fGraphicStackIndex].fTransform; if (fFlipOrigin == kFlip_OriginTransform) { transform.postScale(1, -1); transform.postTranslate(0, fHeight); } // PDF doesn't support kClamp_TileMode, so we simulate it by making // a pattern the size of the drawing service. SkIRect bounds = fGraphicStack[fGraphicStackIndex].fClip.getBounds(); pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds); SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref // A color shader is treated as an invalid shader so we don't have // to set a shader just for a color. if (pdfShader.get() == NULL) { newPaint.setColor(0); // Check for a color shader. SkShader::GradientInfo gradientInfo; SkColor gradientColor; gradientInfo.fColors = &gradientColor; gradientInfo.fColorOffsets = NULL; gradientInfo.fColorCount = 1; if (shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType) { newPaint.setColor(gradientColor); } } } if (pdfShader) { // pdfShader has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fShader != pdfShader.get()) { int resourceIndex = fShaderResources.find(pdfShader.get()); if (resourceIndex < 0) { resourceIndex = fShaderResources.count(); fShaderResources.push(pdfShader.get()); pdfShader->ref(); } fContent.writeText("/Pattern CS /Pattern cs /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" SCN /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" scn\n"); fGraphicStack[fGraphicStackIndex].fShader = pdfShader.get(); } } else { SkColor newColor = newPaint.getColor(); newColor = SkColorSetA(newColor, 0xFF); if (fGraphicStack[fGraphicStackIndex].fShader || fGraphicStack[fGraphicStackIndex].fColor != newColor) { emitPDFColor(newColor, &fContent); fContent.writeText("RG "); emitPDFColor(newColor, &fContent); fContent.writeText("rg\n"); fGraphicStack[fGraphicStackIndex].fColor = newColor; fGraphicStack[fGraphicStackIndex].fShader = NULL; } } SkRefPtr<SkPDFGraphicState> newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint); newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref. // newGraphicState has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fGraphicState != newGraphicState.get()) { int resourceIndex = fGraphicStateResources.find(newGraphicState.get()); if (resourceIndex < 0) { resourceIndex = fGraphicStateResources.count(); fGraphicStateResources.push(newGraphicState.get()); newGraphicState->ref(); } fContent.writeText("/G"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" gs\n"); fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get(); } if (forText) { if (fGraphicStack[fGraphicStackIndex].fTextScaleX != newPaint.getTextScaleX()) { SkScalar scale = newPaint.getTextScaleX(); SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100)); SkPDFScalar::Append(pdfScale, &fContent); fContent.writeText(" Tz\n"); fGraphicStack[fGraphicStackIndex].fTextScaleX = scale; } if (fGraphicStack[fGraphicStackIndex].fTextFill != newPaint.getStyle()) { SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, enum_must_match_value); fContent.writeDecAsText(newPaint.getStyle()); fContent.writeText(" Tr\n"); fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle(); } } }
void SkPicturePlayback::handleOp(SkReadBuffer* reader, DrawType op, uint32_t size, SkCanvas* canvas, const SkMatrix& initialMatrix) { #define BREAK_ON_READ_ERROR(r) if (!r->isValid()) break switch (op) { case NOOP: { SkASSERT(size >= 4); reader->skip(size - 4); } break; case FLUSH: canvas->flush(); break; case CLIP_PATH: { const SkPath& path = fPictureData->getPath(reader); uint32_t packed = reader->readInt(); SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); validate_offsetToRestore(reader, offsetToRestore); BREAK_ON_READ_ERROR(reader); canvas->clipPath(path, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->skip(offsetToRestore - reader->offset()); } } break; case CLIP_REGION: { SkRegion region; reader->readRegion(®ion); uint32_t packed = reader->readInt(); SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); size_t offsetToRestore = reader->readInt(); validate_offsetToRestore(reader, offsetToRestore); BREAK_ON_READ_ERROR(reader); canvas->clipRegion(region, clipOp); if (canvas->isClipEmpty() && offsetToRestore) { reader->skip(offsetToRestore - reader->offset()); } } break; case CLIP_RECT: { SkRect rect; reader->readRect(&rect); uint32_t packed = reader->readInt(); SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); validate_offsetToRestore(reader, offsetToRestore); BREAK_ON_READ_ERROR(reader); canvas->clipRect(rect, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->skip(offsetToRestore - reader->offset()); } } break; case CLIP_RRECT: { SkRRect rrect; reader->readRRect(&rrect); uint32_t packed = reader->readInt(); SkClipOp clipOp = ClipParams_unpackRegionOp(reader, packed); bool doAA = ClipParams_unpackDoAA(packed); size_t offsetToRestore = reader->readInt(); validate_offsetToRestore(reader, offsetToRestore); BREAK_ON_READ_ERROR(reader); canvas->clipRRect(rrect, clipOp, doAA); if (canvas->isClipEmpty() && offsetToRestore) { reader->skip(offsetToRestore - reader->offset()); } } break; case PUSH_CULL: break; // Deprecated, safe to ignore both push and pop. case POP_CULL: break; case CONCAT: { SkMatrix matrix; reader->readMatrix(&matrix); BREAK_ON_READ_ERROR(reader); canvas->concat(matrix); break; } case DRAW_ANNOTATION: { SkRect rect; reader->readRect(&rect); SkString key; reader->readString(&key); sk_sp<SkData> data = reader->readByteArrayAsData(); BREAK_ON_READ_ERROR(reader); SkASSERT(data); canvas->drawAnnotation(rect, key.c_str(), data.get()); } break; case DRAW_ARC: { const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; reader->readRect(&rect); SkScalar startAngle = reader->readScalar(); SkScalar sweepAngle = reader->readScalar(); int useCenter = reader->readInt(); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawArc(rect, startAngle, sweepAngle, SkToBool(useCenter), *paint); } } break; case DRAW_ATLAS: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* atlas = fPictureData->getImage(reader); const uint32_t flags = reader->readUInt(); const int count = reader->readUInt(); const SkRSXform* xform = (const SkRSXform*)reader->skip(count, sizeof(SkRSXform)); const SkRect* tex = (const SkRect*)reader->skip(count, sizeof(SkRect)); const SkColor* colors = nullptr; SkBlendMode mode = SkBlendMode::kDst; if (flags & DRAW_ATLAS_HAS_COLORS) { colors = (const SkColor*)reader->skip(count, sizeof(SkColor)); mode = (SkBlendMode)reader->readUInt(); } const SkRect* cull = nullptr; if (flags & DRAW_ATLAS_HAS_CULL) { cull = (const SkRect*)reader->skip(sizeof(SkRect)); } BREAK_ON_READ_ERROR(reader); canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint); } break; case DRAW_CLEAR: { auto c = reader->readInt(); BREAK_ON_READ_ERROR(reader); canvas->clear(c); } break; case DRAW_DATA: { // This opcode is now dead, just need to skip it for backwards compatibility size_t length = reader->readInt(); (void)reader->skip(length); // skip handles padding the read out to a multiple of 4 } break; case DRAW_DRAWABLE: { auto* d = fPictureData->getDrawable(reader); BREAK_ON_READ_ERROR(reader); canvas->drawDrawable(d); } break; case DRAW_DRAWABLE_MATRIX: { SkMatrix matrix; reader->readMatrix(&matrix); SkDrawable* drawable = fPictureData->getDrawable(reader); BREAK_ON_READ_ERROR(reader); canvas->drawDrawable(drawable, &matrix); } break; case DRAW_DRRECT: { const SkPaint* paint = fPictureData->getPaint(reader); SkRRect outer, inner; reader->readRRect(&outer); reader->readRRect(&inner); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawDRRect(outer, inner, *paint); } } break; case DRAW_EDGEAA_QUAD: { SkRect rect; reader->readRect(&rect); SkCanvas::QuadAAFlags aaFlags = static_cast<SkCanvas::QuadAAFlags>(reader->read32()); SkColor color = reader->read32(); SkBlendMode blend = static_cast<SkBlendMode>(reader->read32()); bool hasClip = reader->readInt(); SkPoint* clip = nullptr; if (hasClip) { clip = (SkPoint*) reader->skip(4, sizeof(SkPoint)); } BREAK_ON_READ_ERROR(reader); canvas->experimental_DrawEdgeAAQuad(rect, clip, aaFlags, color, blend); } break; case DRAW_EDGEAA_IMAGE_SET: { static const size_t kEntryReadSize = 4 * sizeof(uint32_t) + 2 * sizeof(SkRect) + sizeof(SkScalar); static const size_t kMatrixSize = 9 * sizeof(SkScalar); // != sizeof(SkMatrix) int cnt = reader->readInt(); if (!reader->validate(cnt >= 0)) { break; } const SkPaint* paint = fPictureData->getPaint(reader); SkCanvas::SrcRectConstraint constraint = static_cast<SkCanvas::SrcRectConstraint>(reader->readInt()); if (!reader->validate(SkSafeMath::Mul(cnt, kEntryReadSize) <= reader->available())) { break; } // Track minimum necessary clip points and matrices that must be provided to satisfy // the entries. int expectedClips = 0; int maxMatrixIndex = -1; SkAutoTArray<SkCanvas::ImageSetEntry> set(cnt); for (int i = 0; i < cnt && reader->isValid(); ++i) { set[i].fImage = sk_ref_sp(fPictureData->getImage(reader)); reader->readRect(&set[i].fSrcRect); reader->readRect(&set[i].fDstRect); set[i].fMatrixIndex = reader->readInt(); set[i].fAlpha = reader->readScalar(); set[i].fAAFlags = reader->readUInt(); set[i].fHasClip = reader->readInt(); expectedClips += set[i].fHasClip ? 1 : 0; if (set[i].fMatrixIndex > maxMatrixIndex) { maxMatrixIndex = set[i].fMatrixIndex; } } int dstClipCount = reader->readInt(); SkPoint* dstClips = nullptr; if (!reader->validate(expectedClips <= dstClipCount)) { // Entries request more dstClip points than are provided in the buffer break; } else if (dstClipCount > 0) { dstClips = (SkPoint*) reader->skip(dstClipCount, sizeof(SkPoint)); if (dstClips == nullptr) { // Not enough bytes remaining so the reader has been invalidated break; } } int matrixCount = reader->readInt(); if (!reader->validate((maxMatrixIndex + 1) <= matrixCount) || !reader->validate( SkSafeMath::Mul(matrixCount, kMatrixSize) <= reader->available())) { // Entries access out-of-bound matrix indices, given provided matrices or // there aren't enough bytes to provide that many matrices break; } SkTArray<SkMatrix> matrices(matrixCount); for (int i = 0; i < matrixCount && reader->isValid(); ++i) { reader->readMatrix(&matrices.push_back()); } BREAK_ON_READ_ERROR(reader); canvas->experimental_DrawEdgeAAImageSet(set.get(), cnt, dstClips, matrices.begin(), paint, constraint); } break; case DRAW_IMAGE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); SkPoint loc; reader->readPoint(&loc); BREAK_ON_READ_ERROR(reader); canvas->drawImage(image, loc.fX, loc.fY, paint); } break; case DRAW_IMAGE_LATTICE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); SkCanvas::Lattice lattice; (void)SkCanvasPriv::ReadLattice(*reader, &lattice); const SkRect* dst = reader->skipT<SkRect>(); BREAK_ON_READ_ERROR(reader); canvas->drawImageLattice(image, lattice, *dst, paint); } break; case DRAW_IMAGE_NINE: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); SkIRect center; reader->readIRect(¢er); SkRect dst; reader->readRect(&dst); BREAK_ON_READ_ERROR(reader); canvas->drawImageNine(image, center, dst, paint); } break; case DRAW_IMAGE_RECT: { const SkPaint* paint = fPictureData->getPaint(reader); const SkImage* image = fPictureData->getImage(reader); SkRect storage; const SkRect* src = get_rect_ptr(reader, &storage); // may be null SkRect dst; reader->readRect(&dst); // required // DRAW_IMAGE_RECT_STRICT assumes this constraint, and doesn't store it SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint; if (DRAW_IMAGE_RECT == op) { // newer op-code stores the constraint explicitly constraint = (SkCanvas::SrcRectConstraint)reader->readInt(); } BREAK_ON_READ_ERROR(reader); canvas->legacy_drawImageRect(image, src, dst, paint, constraint); } break; case DRAW_OVAL: { const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; reader->readRect(&rect); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawOval(rect, *paint); } } break; case DRAW_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawPaint(*paint); } } break; case DRAW_BEHIND_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); BREAK_ON_READ_ERROR(reader); if (paint) { SkCanvasPriv::DrawBehind(canvas, *paint); } } break; case DRAW_PATCH: { const SkPaint* paint = fPictureData->getPaint(reader); const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts, sizeof(SkPoint)); uint32_t flag = reader->readInt(); const SkColor* colors = nullptr; if (flag & DRAW_VERTICES_HAS_COLORS) { colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners, sizeof(SkColor)); } const SkPoint* texCoords = nullptr; if (flag & DRAW_VERTICES_HAS_TEXS) { texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners, sizeof(SkPoint)); } SkBlendMode bmode = SkBlendMode::kModulate; if (flag & DRAW_VERTICES_HAS_XFER) { unsigned mode = reader->readInt(); if (mode <= (unsigned)SkBlendMode::kLastMode) { bmode = (SkBlendMode)mode; } } BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawPatch(cubics, colors, texCoords, bmode, *paint); } } break; case DRAW_PATH: { const SkPaint* paint = fPictureData->getPaint(reader); const auto& path = fPictureData->getPath(reader); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawPath(path, *paint); } } break; case DRAW_PICTURE: { const auto* pic = fPictureData->getPicture(reader); BREAK_ON_READ_ERROR(reader); canvas->drawPicture(pic); } break; case DRAW_PICTURE_MATRIX_PAINT: { const SkPaint* paint = fPictureData->getPaint(reader); SkMatrix matrix; reader->readMatrix(&matrix); const SkPicture* pic = fPictureData->getPicture(reader); BREAK_ON_READ_ERROR(reader); canvas->drawPicture(pic, &matrix, paint); } break; case DRAW_POINTS: { const SkPaint* paint = fPictureData->getPaint(reader); SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt(); size_t count = reader->readInt(); const SkPoint* pts = (const SkPoint*)reader->skip(count, sizeof(SkPoint)); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawPoints(mode, count, pts, *paint); } } break; case DRAW_RECT: { const SkPaint* paint = fPictureData->getPaint(reader); SkRect rect; reader->readRect(&rect); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawRect(rect, *paint); } } break; case DRAW_REGION: { const SkPaint* paint = fPictureData->getPaint(reader); SkRegion region; reader->readRegion(®ion); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawRegion(region, *paint); } } break; case DRAW_RRECT: { const SkPaint* paint = fPictureData->getPaint(reader); SkRRect rrect; reader->readRRect(&rrect); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawRRect(rrect, *paint); } } break; case DRAW_SHADOW_REC: { const auto& path = fPictureData->getPath(reader); SkDrawShadowRec rec; reader->readPoint3(&rec.fZPlaneParams); reader->readPoint3(&rec.fLightPos); rec.fLightRadius = reader->readScalar(); if (reader->isVersionLT(SkReadBuffer::kTwoColorDrawShadow_Version)) { SkScalar ambientAlpha = reader->readScalar(); SkScalar spotAlpha = reader->readScalar(); SkColor color = reader->read32(); rec.fAmbientColor = SkColorSetA(color, SkColorGetA(color)*ambientAlpha); rec.fSpotColor = SkColorSetA(color, SkColorGetA(color)*spotAlpha); } else { rec.fAmbientColor = reader->read32(); rec.fSpotColor = reader->read32(); } rec.fFlags = reader->read32(); BREAK_ON_READ_ERROR(reader); canvas->private_draw_shadow_rec(path, rec); } break; case DRAW_TEXT_BLOB: { const SkPaint* paint = fPictureData->getPaint(reader); const SkTextBlob* blob = fPictureData->getTextBlob(reader); SkScalar x = reader->readScalar(); SkScalar y = reader->readScalar(); BREAK_ON_READ_ERROR(reader); if (paint) { canvas->drawTextBlob(blob, x, y, *paint); } } break; case DRAW_VERTICES_OBJECT: { const SkPaint* paint = fPictureData->getPaint(reader); const SkVertices* vertices = fPictureData->getVertices(reader); const int boneCount = reader->readInt(); const SkVertices::Bone* bones = boneCount ? (const SkVertices::Bone*) reader->skip(boneCount, sizeof(SkVertices::Bone)) : nullptr; SkBlendMode bmode = reader->read32LE(SkBlendMode::kLastMode); BREAK_ON_READ_ERROR(reader); if (paint && vertices) { canvas->drawVertices(vertices, bones, boneCount, bmode, *paint); } } break; case RESTORE: canvas->restore(); break; case ROTATE: { auto deg = reader->readScalar(); canvas->rotate(deg); } break; case SAVE: canvas->save(); break; case SAVE_BEHIND: { uint32_t flags = reader->readInt(); const SkRect* subset = nullptr; SkRect storage; if (flags & SAVEBEHIND_HAS_SUBSET) { reader->readRect(&storage); subset = &storage; } SkCanvasPriv::SaveBehind(canvas, subset); } break; case SAVE_LAYER_SAVEFLAGS_DEPRECATED: { SkRect storage; const SkRect* boundsPtr = get_rect_ptr(reader, &storage); const SkPaint* paint = fPictureData->getPaint(reader); auto flags = SkCanvasPriv::LegacySaveFlagsToSaveLayerFlags(reader->readInt()); BREAK_ON_READ_ERROR(reader); canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags)); } break; case SAVE_LAYER_SAVELAYERREC: { SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, nullptr, nullptr, 0); SkMatrix clipMatrix; const uint32_t flatFlags = reader->readInt(); SkRect bounds; if (flatFlags & SAVELAYERREC_HAS_BOUNDS) { reader->readRect(&bounds); rec.fBounds = &bounds; } if (flatFlags & SAVELAYERREC_HAS_PAINT) { rec.fPaint = fPictureData->getPaint(reader); } if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { if (const auto* paint = fPictureData->getPaint(reader)) { rec.fBackdrop = paint->getImageFilter(); } } if (flatFlags & SAVELAYERREC_HAS_FLAGS) { rec.fSaveLayerFlags = reader->readInt(); } if (flatFlags & SAVELAYERREC_HAS_CLIPMASK) { rec.fClipMask = fPictureData->getImage(reader); } if (flatFlags & SAVELAYERREC_HAS_CLIPMATRIX) { reader->readMatrix(&clipMatrix); rec.fClipMatrix = &clipMatrix; } BREAK_ON_READ_ERROR(reader); canvas->saveLayer(rec); } break; case SCALE: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); canvas->scale(sx, sy); } break; case SET_MATRIX: { SkMatrix matrix; reader->readMatrix(&matrix); matrix.postConcat(initialMatrix); canvas->setMatrix(matrix); } break; case SKEW: { SkScalar sx = reader->readScalar(); SkScalar sy = reader->readScalar(); canvas->skew(sx, sy); } break; case TRANSLATE: { SkScalar dx = reader->readScalar(); SkScalar dy = reader->readScalar(); canvas->translate(dx, dy); } break; default: reader->validate(false); // unknown op break; } #undef BREAK_ON_READ_ERROR }
static SkColor modAlpha(SkColor c, int alpha) { int scale = alpha + (alpha >> 7); int a = SkColorGetA(c) * scale >> 8; return SkColorSetA(c, a); }
// Reduce to a single drawBitmapRectToRect call by folding the clipRect's into // the src and dst Rects and the saveLayer paints into the drawBitmapRectToRect's // paint. static void apply_7(SkDebugCanvas* canvas, int curCommand) { SkSaveLayerCommand* saveLayer0 = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+2); SkSaveLayerCommand* saveLayer1 = (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand+5); SkClipRectCommand* clip2 = (SkClipRectCommand*) canvas->getDrawCommandAt(curCommand+7); SkDrawBitmapRectCommand* dbmr = (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+8); SkScalar newSrcLeft = dbmr->srcRect()->fLeft + clip2->rect().fLeft - dbmr->dstRect().fLeft; SkScalar newSrcTop = dbmr->srcRect()->fTop + clip2->rect().fTop - dbmr->dstRect().fTop; SkRect newSrc = SkRect::MakeXYWH(newSrcLeft, newSrcTop, clip2->rect().width(), clip2->rect().height()); dbmr->setSrcRect(newSrc); dbmr->setDstRect(clip2->rect()); SkColor color = 0xFF000000; int a0, a1; const SkPaint* saveLayerPaint0 = saveLayer0->paint(); if (NULL != saveLayerPaint0) { color = saveLayerPaint0->getColor(); a0 = SkColorGetA(color); } else { a0 = 0xFF; } const SkPaint* saveLayerPaint1 = saveLayer1->paint(); if (NULL != saveLayerPaint1) { color = saveLayerPaint1->getColor(); a1 = SkColorGetA(color); } else { a1 = 0xFF; } int newA = SkMulDiv255Round(a0, a1); SkASSERT(newA <= 0xFF); SkPaint* dbmrPaint = dbmr->paint(); if (NULL != dbmrPaint) { SkColor newColor = SkColorSetA(dbmrPaint->getColor(), newA); dbmrPaint->setColor(newColor); } else { SkColor newColor = SkColorSetA(color, newA); SkPaint newPaint; newPaint.setColor(newColor); dbmr->setPaint(newPaint); } // remove everything except the drawbitmaprect canvas->deleteDrawCommandAt(curCommand+13); // restore canvas->deleteDrawCommandAt(curCommand+12); // restore canvas->deleteDrawCommandAt(curCommand+11); // restore canvas->deleteDrawCommandAt(curCommand+10); // restore canvas->deleteDrawCommandAt(curCommand+9); // restore canvas->deleteDrawCommandAt(curCommand+7); // clipRect canvas->deleteDrawCommandAt(curCommand+6); // save canvas->deleteDrawCommandAt(curCommand+5); // saveLayer canvas->deleteDrawCommandAt(curCommand+4); // clipRect canvas->deleteDrawCommandAt(curCommand+3); // save canvas->deleteDrawCommandAt(curCommand+2); // saveLayer canvas->deleteDrawCommandAt(curCommand+1); // clipRect canvas->deleteDrawCommandAt(curCommand); // save }