DisplayListPattern::DisplayListPattern(PassRefPtr<DisplayList> displayList, RepeatMode mode) : Pattern(mode) , m_tileDisplayList(displayList) { // All current clients use RepeatModeXY, so we only support this mode for now. ASSERT(isRepeatXY()); // FIXME: we don't have a good way to account for DL memory utilization. }
PicturePattern::PicturePattern(PassRefPtr<const SkPicture> picture, RepeatMode mode) : Pattern(mode) , m_tilePicture(picture) { // All current clients use RepeatModeXY, so we only support this mode for now. ASSERT(isRepeatXY()); // FIXME: we don't have a good way to account for DL memory utilization. }
PassRefPtr<SkShader> BitmapPattern::createShader() { if (m_tileImage.isNull()) { return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); } SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation); if (isRepeatXY()) { return adoptRef(SkShader::CreateBitmapShader(m_tileImage, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } return BitmapPatternBase::createShader(); }
sk_sp<SkShader> ImagePattern::createShader(const SkMatrix& localMatrix) { if (!m_tileImage) return SkShader::MakeColorShader(SK_ColorTRANSPARENT); if (isRepeatXY()) { // Fast path: for repeatXY we just return a shader from the original image. return m_tileImage->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix); } // Skia does not have a "draw the tile only once" option. Clamp_TileMode // repeats the last line of the image after drawing one tile. To avoid // filling the space with arbitrary pixels, this workaround forces the // image to have a line of transparent pixels on the "repeated" edge(s), // thus causing extra space to be transparent filled. SkShader::TileMode tileModeX = isRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; SkShader::TileMode tileModeY = isRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; int borderPixelX = isRepeatX() ? 0 : 1; int borderPixelY = isRepeatY() ? 0 : 1; // Create a transparent image 2 pixels wider and/or taller than the // original, then copy the orignal into the middle of it. // FIXME: Is there a better way to pad (not scale) an image in skia? sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(m_tileImage->width() + 2 * borderPixelX, m_tileImage->height() + 2 * borderPixelY); if (!surface) return SkShader::MakeColorShader(SK_ColorTRANSPARENT); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); surface->getCanvas()->drawImage(m_tileImage, borderPixelX, borderPixelY, &paint); m_previousLocalMatrix = localMatrix; SkMatrix adjustedMatrix(localMatrix); adjustedMatrix.postTranslate(-borderPixelX, -borderPixelY); return surface->makeImageSnapshot()->makeShader(tileModeX, tileModeY, &adjustedMatrix); }
PassRefPtr<SkShader> ImagePattern::createShader() { if (!m_tileImage) return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation); if (isRepeatXY()) { // Fast path: for repeatXY we just return a shader from the original image. return adoptRef(m_tileImage->newShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } // Skia does not have a "draw the tile only once" option. Clamp_TileMode // repeats the last line of the image after drawing one tile. To avoid // filling the space with arbitrary pixels, this workaround forces the // image to have a line of transparent pixels on the "repeated" edge(s), // thus causing extra space to be transparent filled. SkShader::TileMode tileModeX = isRepeatX() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; SkShader::TileMode tileModeY = isRepeatY() ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; int expandW = isRepeatX() ? 0 : 1; int expandH = isRepeatY() ? 0 : 1; // Create a transparent image 1 pixel wider and/or taller than the // original, then copy the orignal into it. // FIXME: Is there a better way to pad (not scale) an image in skia? RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul( m_tileImage->width() + expandW, m_tileImage->height() + expandH)); if (!surface) return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); surface->getCanvas()->clear(SK_ColorTRANSPARENT); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); surface->getCanvas()->drawImage(m_tileImage.get(), 0, 0, &paint); RefPtr<SkImage> expandedImage = adoptRef(surface->newImageSnapshot()); return adoptRef(expandedImage->newShader(tileModeX, tileModeY, &localMatrix)); }
bool ImagePattern::isLocalMatrixChanged(const SkMatrix& localMatrix) const { if (isRepeatXY()) return Pattern::isLocalMatrixChanged(localMatrix); return localMatrix != m_previousLocalMatrix; }