void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) { SkBitmapRef* image = this->nativeImageForCurrentFrame(); if (!image) { // If it's too early we won't have an image yet. return; } // in case we get called with an incomplete bitmap const SkBitmap& bitmap = image->bitmap(); if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) { return; } SkRect dstR; android_setrect(&dstR, destRect); if (dstR.isEmpty()) { return; } SkCanvas* canvas = ctxt->platformContext()->mCanvas; SkPaint paint; SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); paint.setShader(shader)->unref(); // now paint is the only owner of shader paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp)); paint.setFilterBitmap(true); SkMatrix matrix(patternTransform); float scaleX = (float)image->origWidth() / bitmap.width(); float scaleY = (float)image->origHeight() / bitmap.height(); matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY)); matrix.postTranslate(SkFloatToScalar(phase.x()), SkFloatToScalar(phase.y())); shader->setLocalMatrix(matrix); canvas->drawRect(dstR, paint); #ifdef TRACE_SUBSAMPLED_BITMAPS if (bitmap.width() != image->origWidth() || bitmap.height() != image->origHeight()) { SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n", bitmap.width(), bitmap.height(), image->origWidth(), image->origHeight(), SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height())); } #endif }
SkShader* Gradient::getShader(SkShader::TileMode mode) { if (NULL == m_gradient) m_gradient = new PlatformGradientRec; else if (mode == m_gradient->m_tileMode) return m_gradient->m_shader; // need to ensure that the m_stops array is sorted. We call getColor() // which, as a side effect, does the sort. // TODO: refactor Gradient.h to formally expose a sort method { float r, g, b, a; this->getColor(0, &r, &g, &b, &a); } SkPoint pts[2] = { m_p0, m_p1 }; // convert to SkPoint const size_t count = m_stops.size(); SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar))); SkColor* colors = (SkColor*)storage.get(); SkScalar* pos = (SkScalar*)(colors + count); Vector<ColorStop>::iterator iter = m_stops.begin(); for (int i = 0; iter != m_stops.end(); i++) { pos[i] = SkFloatToScalar(iter->stop); colors[i] = SkColorSetARGB(F2B(iter->alpha), F2B(iter->red), F2B(iter->green), F2B(iter->blue)); ++iter; } SkShader* s; if (m_radial) s = SkGradientShader::CreateTwoPointRadial(pts[0], SkFloatToScalar(m_r0), pts[1], SkFloatToScalar(m_r1), colors, pos, count, mode); else s = SkGradientShader::CreateLinear(pts, colors, pos, count, mode); if (NULL == s) s = new SkColorShader(0); // zap our previous shader, if present SkSafeUnref(m_gradient->m_shader); m_gradient->m_shader = s; m_gradient->m_tileMode = mode; SkMatrix matrix = m_gradientSpaceTransformation; s->setLocalMatrix(matrix); return s; }
ImageView() { SkImageRef_GlobalPool::SetRAMBudget(32 * 1024); int i, N = SK_ARRAY_COUNT(gNames); fBitmaps = new SkBitmap[N]; for (i = 0; i < N; i++) { SkString str("/skimages/"); str.append(gNames[i]); SkFILEStream* stream = new SkFILEStream(str.c_str()); SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config, gNames[i]); if (i & 1) fBitmaps[i].buildMipMap(); stream->unref(); } fShader = SkShader::CreateBitmapShader(fBitmaps[5], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); if (true) { SkMatrix m; m.setRotate(SkIntToScalar(30)); fShader->setLocalMatrix(m); } #if 0 SkImageRef::DumpPool(); for (i = 0; i < N; i++) { SkBitmap& bm = fBitmaps[i]; SkDebugf("<%s> addr=%p", gNames[i], bm.getPixels()); bool success = bm.lockPixels(); SkDebugf(" addr=%d", bm.getPixels()); if (success) bm.unlockPixels(); SkDebugf(" addr=%p", bm.getPixels()); success = bm.lockPixels(); SkDebugf(" addr=%d", bm.getPixels()); if (success) bm.unlockPixels(); SkDebugf("\n"); } SkImageRef::DumpPool(); #endif }
static void copybits(SkCanvas* canvas, const SkBitmap& bm, const SkRect& dst, const SkPaint& paint) { SkRect src; SkMatrix matrix; src.set(0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())); if (matrix.setRectToRect(src, dst)) { SkPaint p(paint); SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kNo_FilterType, SkShader::kClamp_TileMode); p.setShader(shader)->unref(); shader->setLocalMatrix(matrix); canvas->drawRect(dst, p); } }
static SkShader* createChecker() { // SkColor colors[] = { 0xFFFDFDFD, 0xFFF4F4F4 }; SkColor colors[] = { 0xFFFFFFFF, 0xFFFFFFFF }; SkBitmap bm; bm.allocN32Pixels(2, 2); bm.lockPixels(); *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(colors[0]); *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(colors[1]); SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(12, 12); s->setLocalMatrix(m); return s; }
void PlatformGraphicsContextSkia::drawBitmapPattern( const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator compositeOp, const FloatRect& destRect) { SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); shader->setLocalMatrix(matrix); SkPaint paint; setupPaintCommon(&paint); paint.setAlpha(getNormalizedAlpha()); paint.setShader(shader)->unref(); paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); fixPaintForBitmapsThatMaySeam(&paint); mCanvas->drawRect(destRect, paint); }
static SkShader* make_bg_shader() { SkBitmap bm; bm.allocN32Pixels(2, 2); *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF; *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, 0xCC, 0xCC); SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); return s; }
static void setBitmapDash(SkPaint* paint, int width) { SkColor c = paint->getColor(); SkBitmap bm; bm.allocN32Pixels(2, 1); bm.lockPixels(); *bm.getAddr32(0, 0) = SkPreMultiplyARGB(0xFF, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); *bm.getAddr32(1, 0) = 0; bm.unlockPixels(); SkMatrix matrix; matrix.setScale(SkIntToScalar(width), SK_Scalar1); SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode); s->setLocalMatrix(matrix); paint->setShader(s)->unref(); }
static void drawmarshmallow(SkCanvas* canvas) { SkBitmap bitmap; SkPaint paint; SkRect r; SkMatrix m; SkImageDecoder::DecodeFile("/Users/reed/Downloads/3elfs.jpg", &bitmap); SkShader* s = SkShader::CreateBitmapShader(bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); paint.setShader(s)->unref(); m.setTranslate(SkIntToScalar(250), SkIntToScalar(134)); s->setLocalMatrix(m); r.set(SkIntToScalar(250), SkIntToScalar(134), SkIntToScalar(250 + 449), SkIntToScalar(134 + 701)); paint.setFlags(2); canvas->drawRect(r, paint); }
void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, int width, bool grammar) { if (paintingDisabled()) return; // Create the pattern we'll use to draw the underline. static SkBitmap* misspellBitmap = 0; if (!misspellBitmap) { // We use a 2-pixel-high misspelling indicator because that seems to be // what WebKit is designed for, and how much room there is in a typical // page for it. const int rowPixels = 32; // Must be multiple of 4 for pattern below. const int colPixels = 2; misspellBitmap = new SkBitmap; misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); misspellBitmap->allocPixels(); misspellBitmap->eraseARGB(0, 0, 0, 0); const uint32_t lineColor = 0xFFFF0000; // Opaque red. const uint32_t antiColor = 0x60600000; // Semitransparent red. // Pattern: X o o X o o X // o X o o X o uint32_t* row1 = misspellBitmap->getAddr32(0, 0); uint32_t* row2 = misspellBitmap->getAddr32(0, 1); for (int x = 0; x < rowPixels; x++) { switch (x % 4) { case 0: row1[x] = lineColor; break; case 1: row1[x] = antiColor; row2[x] = antiColor; break; case 2: row2[x] = lineColor; break; case 3: row1[x] = antiColor; row2[x] = antiColor; break; } } } // Offset it vertically by 1 so that there's some space under the text. SkScalar originX = SkIntToScalar(pt.x()); SkScalar originY = SkIntToScalar(pt.y()) + 1; // Make a shader for the bitmap with an origin of the box we'll draw. This // shader is refcounted and will have an initial refcount of 1. SkShader* shader = SkShader::CreateBitmapShader( *misspellBitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix matrix; matrix.reset(); matrix.postTranslate(originX, originY); shader->setLocalMatrix(matrix); // Assign the shader to the paint & release our reference. The paint will // now own the shader and the shader will be destroyed when the paint goes // out of scope. SkPaint paint; paint.setShader(shader); shader->unref(); SkRect rect; rect.set(originX, originY, originX + SkIntToScalar(width), originY + SkIntToScalar(misspellBitmap->height())); platformContext()->canvas()->drawRect(rect, paint); }
void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { FloatRect normSrcRect = normalizeRect(floatSrcRect); if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw NativeImageSkia* bitmap = nativeImageForCurrentFrame(); if (!bitmap) return; SkIRect srcRect = enclosingIntRect(normSrcRect); // Figure out what size the bitmap will be in the destination. The // destination rect is the bounds of the pattern, we need to use the // matrix to see how big it will be. float destBitmapWidth, destBitmapHeight; TransformDimensions(patternTransform, srcRect.width(), srcRect.height(), &destBitmapWidth, &destBitmapHeight); // Compute the resampling mode. ResamplingMode resampling; if (context->platformContext()->isAccelerated() || context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight); // Load the transform WebKit requested. SkMatrix matrix(patternTransform); SkShader* shader; if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. int width = static_cast<int>(destBitmapWidth); int height = static_cast<int>(destBitmapHeight); SkBitmap resampled = bitmap->resizedBitmap(srcRect, width, height); shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); // Since we just resized the bitmap, we need to undo the scale set in // the image transform. matrix.setScaleX(SkIntToScalar(1)); matrix.setScaleY(SkIntToScalar(1)); } else { // No need to do nice resampling. SkBitmap srcSubset; bitmap->bitmap().extractSubset(&srcSubset, srcRect); shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); } // We also need to translate it such that the origin of the pattern is the // origin of the destination rect, which is what WebKit expects. Skia uses // the coordinate system origin as the base for the patter. If WebKit wants // a shifted image, it will shift it from there using the patternTransform. float adjustedX = phase.x() + normSrcRect.x() * narrowPrecisionToFloat(patternTransform.a()); float adjustedY = phase.y() + normSrcRect.y() * narrowPrecisionToFloat(patternTransform.d()); matrix.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); shader->setLocalMatrix(matrix); SkPaint paint; paint.setShader(shader)->unref(); paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); context->platformContext()->paintSkPaint(destRect, paint); }
void DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator) { MarkChanged(); mCanvas->save(SkCanvas::kMatrix_SaveFlag); mCanvas->resetMatrix(); uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag | SkBlurMaskFilter::kIgnoreTransform_BlurFlag; const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap(); SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); SkMatrix matrix; matrix.reset(); matrix.setTranslateX(SkFloatToScalar(aDest.x)); matrix.setTranslateY(SkFloatToScalar(aDest.y)); shader->setLocalMatrix(matrix); SkLayerDrawLooper* dl = new SkLayerDrawLooper; SkLayerDrawLooper::LayerInfo info; info.fPaintBits |= SkLayerDrawLooper::kShader_Bit; SkPaint *layerPaint = dl->addLayer(info); layerPaint->setShader(shader); info.fPaintBits = 0; info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; info.fColorMode = SkXfermode::kDst_Mode; info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); info.fPostTranslate = true; SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags); SkColor color = ColorToSkColor(aColor, 1); SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode); layerPaint = dl->addLayer(info); SkSafeUnref(layerPaint->setMaskFilter(mf)); SkSafeUnref(layerPaint->setColorFilter(cf)); layerPaint->setColor(color); // TODO: This is using the rasterizer to calculate an alpha mask // on both the shadow and normal layers. We should fix this // properly so it only happens for the shadow layer SkLayerRasterizer *raster = new SkLayerRasterizer(); SkPaint maskPaint; SkSafeUnref(maskPaint.setShader(shader)); raster->addLayer(maskPaint, 0, 0); SkPaint paint; paint.setAntiAlias(true); SkSafeUnref(paint.setRasterizer(raster)); paint.setXfermodeMode(GfxOpToSkiaOp(aOperator)); SkSafeUnref(paint.setLooper(dl)); SkRect rect = RectToSkRect(Rect(Float(aDest.x), Float(aDest.y), Float(bitmap.width()), Float(bitmap.height()))); mCanvas->drawRect(rect, paint); mCanvas->restore(); }
void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, float width, DocumentMarkerLineStyle style) { if (paintingDisabled()) return; // Create the pattern we'll use to draw the underline. int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0; static SkBitmap* misspellBitmap[2] = { 0, 0 }; if (!misspellBitmap[index]) { #if PLATFORM(CHROMIUM) && OS(DARWIN) // Match the artwork used by the Mac. const int rowPixels = 4; const int colPixels = 3; #else // We use a 2-pixel-high misspelling indicator because that seems to be // what WebKit is designed for, and how much room there is in a typical // page for it. const int rowPixels = 32; // Must be multiple of 4 for pattern below. const int colPixels = 2; #endif misspellBitmap[index] = new SkBitmap; misspellBitmap[index]->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); misspellBitmap[index]->allocPixels(); misspellBitmap[index]->eraseARGB(0, 0, 0, 0); #if PLATFORM(CHROMIUM) && OS(DARWIN) const uint32_t colors[2][6] = { { 0x2A2A0600, 0x57571000, 0xA8A81B00, 0xBFBF1F00, 0x70701200, 0xE0E02400 }, { 0x2A001503, 0x57002A08, 0xA800540D, 0xBF005F0F, 0x70003809, 0xE0007012 } }; const uint32_t transparentColor = 0x00000000; // Pattern: a b a a b a // c d c c d c // e f e e f e for (int x = 0; x < colPixels; ++x) { uint32_t* row = misspellBitmap[index]->getAddr32(0, x); row[0] = colors[index][x * 2]; row[1] = colors[index][x * 2 + 1]; row[2] = colors[index][x * 2]; row[3] = transparentColor; } #else static const uint32_t lineColors[2] = { 0xFF << SK_A32_SHIFT | 0xFF << SK_R32_SHIFT, // Opaque red. 0xFF << SK_A32_SHIFT | 0xC0 << SK_R32_SHIFT | 0xC0 << SK_G32_SHIFT | 0xC0 << SK_B32_SHIFT, // Opaque gray. }; static const uint32_t antiColors[2] = { 0x60 << SK_A32_SHIFT | 0x60 << SK_R32_SHIFT, // Semitransparent red 0xFF << SK_A32_SHIFT | 0xC0 << SK_R32_SHIFT | 0xC0 << SK_G32_SHIFT | 0xC0 << SK_B32_SHIFT, // Semitransparent gray }; const uint32_t lineColor = lineColors[index]; const uint32_t antiColor = antiColors[index]; // Pattern: X o o X o o X // o X o o X o uint32_t* row1 = misspellBitmap[index]->getAddr32(0, 0); uint32_t* row2 = misspellBitmap[index]->getAddr32(0, 1); for (int x = 0; x < rowPixels; x++) { switch (x % 4) { case 0: row1[x] = lineColor; break; case 1: row1[x] = antiColor; row2[x] = antiColor; break; case 2: row2[x] = lineColor; break; case 3: row1[x] = antiColor; row2[x] = antiColor; break; } } #endif } SkScalar originX = WebCoreFloatToSkScalar(pt.x()); #if PLATFORM(CHROMIUM) && OS(DARWIN) SkScalar originY = WebCoreFloatToSkScalar(pt.y()); // Make sure to draw only complete dots. int rowPixels = misspellBitmap[index]->width(); float widthMod = fmodf(width, rowPixels); if (rowPixels - widthMod > 1) width -= widthMod; #else // Offset it vertically by 1 so that there's some space under the text. SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1; #endif // Make a shader for the bitmap with an origin of the box we'll draw. This // shader is refcounted and will have an initial refcount of 1. SkShader* shader = SkShader::CreateBitmapShader( *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix matrix; matrix.reset(); matrix.postTranslate(originX, originY); shader->setLocalMatrix(matrix); // Assign the shader to the paint & release our reference. The paint will // now own the shader and the shader will be destroyed when the paint goes // out of scope. SkPaint paint; paint.setShader(shader); shader->unref(); SkRect rect; rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width), originY + SkIntToScalar(misspellBitmap[index]->height())); platformContext()->canvas()->drawRect(rect, paint); platformContext()->didDrawRect(rect, paint); }
static SkShader* source_to_sk_shader (cairo_skia_context_t *cr, const cairo_pattern_t *pattern) { SkShader *shader = NULL; if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; return new SkColorShader (color_to_sk (solid->color)); } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_t *surface = surface_from_pattern (pattern); cr->source = cairo_surface_reference (surface); if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; shader = SkShader::CreateBitmapShader (*esurf->bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } else { SkBitmap bitmap; if (! _cairo_surface_is_image (surface)) { cairo_status_t status; status = _cairo_surface_acquire_source_image (surface, &cr->source_image, &cr->source_extra); if (status) return NULL; surface = &cr->source_image->base; } if (unlikely (! surface_to_sk_bitmap (surface, bitmap))) return NULL; shader = SkShader::CreateBitmapShader (bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */) { cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; SkColor colors_stack[10]; SkScalar pos_stack[10]; SkColor *colors = colors_stack; SkScalar *pos = pos_stack; if (gradient->n_stops > 10) { colors = new SkColor[gradient->n_stops]; pos = new SkScalar[gradient->n_stops]; } for (unsigned int i = 0; i < gradient->n_stops; i++) { pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset); colors[i] = color_stop_to_sk (gradient->stops[i].color); } if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; SkPoint points[2]; points[0].set (SkFloatToScalar (linear->pd1.x), SkFloatToScalar (linear->pd1.y)); points[1].set (SkFloatToScalar (linear->pd2.x), SkFloatToScalar (linear->pd2.y)); shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, extend_to_sk (pattern->extend)); } else { // XXX todo -- implement real radial shaders in Skia } if (gradient->n_stops > 10) { delete [] colors; delete [] pos; } } if (shader && ! _cairo_matrix_is_identity (&pattern->matrix)) shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix)); return shader; }
void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { #if PLATFORM(CHROMIUM) TRACE_EVENT0("skia", "Image::drawPattern"); #endif FloatRect normSrcRect = normalizeRect(floatSrcRect); if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw NativeImageSkia* bitmap = nativeImageForCurrentFrame(); if (!bitmap) return; SkMatrix ctm = context->platformContext()->canvas()->getTotalMatrix(); SkMatrix totalMatrix; totalMatrix.setConcat(ctm, patternTransform); // Figure out what size the bitmap will be in the destination. The // destination rect is the bounds of the pattern, we need to use the // matrix to see how big it will be. SkRect destRectTarget; totalMatrix.mapRect(&destRectTarget, normSrcRect); float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); // Compute the resampling mode. ResamplingMode resampling; if (context->platformContext()->isAccelerated() || context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else resampling = computeResamplingMode(totalMatrix, *bitmap, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); resampling = limitResamplingMode(context->platformContext(), resampling); // Load the transform WebKit requested. SkMatrix matrix(patternTransform); SkShader* shader; if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. float scaleX = destBitmapWidth / normSrcRect.width(); float scaleY = destBitmapHeight / normSrcRect.height(); SkRect scaledSrcRect; SkIRect enclosingScaledSrcRect; // The image fragment generated here is not exactly what is // requested. The scale factor used is approximated and image // fragment is slightly larger to align to integer // boundaries. SkBitmap resampled = extractScaledImageFragment(*bitmap, normSrcRect, scaleX, scaleY, &scaledSrcRect, &enclosingScaledSrcRect); shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); // Since we just resized the bitmap, we need to remove the scale // applied to the pixels in the bitmap shader. This means we need // CTM * patternTransform to have identity scale. Since we // can't modify CTM (or the rectangle will be drawn in the wrong // place), we must set patternTransform's scale to the inverse of // CTM scale. matrix.setScaleX(ctm.getScaleX() ? 1 / ctm.getScaleX() : 1); matrix.setScaleY(ctm.getScaleY() ? 1 / ctm.getScaleY() : 1); } else { // No need to do nice resampling. SkBitmap srcSubset; bitmap->bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect)); shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); } // We also need to translate it such that the origin of the pattern is the // origin of the destination rect, which is what WebKit expects. Skia uses // the coordinate system origin as the base for the patter. If WebKit wants // a shifted image, it will shift it from there using the patternTransform. float adjustedX = phase.x() + normSrcRect.x() * narrowPrecisionToFloat(patternTransform.a()); float adjustedY = phase.y() + normSrcRect.y() * narrowPrecisionToFloat(patternTransform.d()); matrix.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); shader->setLocalMatrix(matrix); SkPaint paint; paint.setShader(shader)->unref(); paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); context->platformContext()->paintSkPaint(destRect, paint); }
void SkDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint) { SkMatrix matrix; SkRect bitmapBounds, tmpSrc, tmpDst; SkBitmap tmpBitmap; bitmapBounds.isetWH(bitmap.width(), bitmap.height()); // Compute matrix from the two rectangles if (src) { tmpSrc = *src; } else { tmpSrc = bitmapBounds; } matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); const SkRect* dstPtr = &dst; const SkBitmap* bitmapPtr = &bitmap; // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if // needed (if the src was clipped). No check needed if src==null. if (src) { if (!bitmapBounds.contains(*src)) { if (!tmpSrc.intersect(bitmapBounds)) { return; // nothing to draw } // recompute dst, based on the smaller tmpSrc matrix.mapRect(&tmpDst, tmpSrc); dstPtr = &tmpDst; } // since we may need to clamp to the borders of the src rect within // the bitmap, we extract a subset. SkIRect srcIR; tmpSrc.roundOut(&srcIR); if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { return; } bitmapPtr = &tmpBitmap; // Since we did an extract, we need to adjust the matrix accordingly SkScalar dx = 0, dy = 0; if (srcIR.fLeft > 0) { dx = SkIntToScalar(srcIR.fLeft); } if (srcIR.fTop > 0) { dy = SkIntToScalar(srcIR.fTop); } if (dx || dy) { matrix.preTranslate(dx, dy); } SkRect extractedBitmapBounds; extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); if (extractedBitmapBounds == tmpSrc) { // no fractional part in src, we can just call drawBitmap goto USE_DRAWBITMAP; } } else { USE_DRAWBITMAP: // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. this->drawBitmap(draw, *bitmapPtr, matrix, paint); return; } // construct a shader, so we can call drawRect with the dst SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); if (NULL == s) { return; } s->setLocalMatrix(matrix); SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); paintWithShader.setShader(s)->unref(); // Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves. this->drawRect(draw, *dstPtr, paintWithShader); }
virtual void onDraw(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); this->drawBG(canvas); const struct { SkXfermode::Mode fMode; const char* fLabel; } gModes[] = { { SkXfermode::kClear_Mode, "Clear" }, { SkXfermode::kSrc_Mode, "Src" }, { SkXfermode::kDst_Mode, "Dst" }, { SkXfermode::kSrcOver_Mode, "SrcOver" }, { SkXfermode::kDstOver_Mode, "DstOver" }, { SkXfermode::kSrcIn_Mode, "SrcIn" }, { SkXfermode::kDstIn_Mode, "DstIn" }, { SkXfermode::kSrcOut_Mode, "SrcOut" }, { SkXfermode::kDstOut_Mode, "DstOut" }, { SkXfermode::kSrcATop_Mode, "SrcATop" }, { SkXfermode::kDstATop_Mode, "DstATop" }, { SkXfermode::kXor_Mode, "Xor" }, { SkXfermode::kPlus_Mode, "Plus" }, { SkXfermode::kMultiply_Mode, "Multiply" }, { SkXfermode::kScreen_Mode, "Screen" }, { SkXfermode::kOverlay_Mode, "Overlay" }, { SkXfermode::kDarken_Mode, "Darken" }, { SkXfermode::kLighten_Mode, "Lighten" }, { SkXfermode::kColorDodge_Mode, "ColorDodge" }, { SkXfermode::kColorBurn_Mode, "ColorBurn" }, { SkXfermode::kHardLight_Mode, "HardLight" }, { SkXfermode::kSoftLight_Mode, "SoftLight" }, { SkXfermode::kDifference_Mode, "Difference" }, { SkXfermode::kExclusion_Mode, "Exclusion" }, }; const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkShader* s = SkShader::CreateBitmapShader(fBG, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); SkPaint labelP; labelP.setAntiAlias(true); labelP.setTextAlign(SkPaint::kCenter_Align); const int W = 5; SkScalar x0 = 0; for (int twice = 0; twice < 2; twice++) { SkScalar x = x0, y = 0; for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop); canvas->restore(); r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); #if 1 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); #endif x += w + SkIntToScalar(10); if ((i % W) == W - 1) { x = x0; y += h + SkIntToScalar(30); } } x0 += SkIntToScalar(400); } s->unref(); }
// test drawing with strips of fading gradient above and below static void test_fade(SkCanvas* canvas) { SkAutoCanvasRestore ar(canvas, true); SkRect r; SkPaint p; p.setAlpha(0x88); SkAutoCanvasRestore(canvas, false); // create the layers r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100)); canvas->clipRect(r); r.fBottom = SkIntToScalar(20); canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag)); r.fTop = SkIntToScalar(80); r.fBottom = SkIntToScalar(100); canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag)); // now draw the "content" if (true) { r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100)); canvas->saveLayerAlpha(&r, 0x80); SkPaint p; p.setColor(SK_ColorRED); p.setAntiAlias(true); canvas->drawOval(r, p); dump_layers("inside layer alpha", canvas); canvas->restore(); } else { r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100)); SkPaint p; p.setColor(SK_ColorRED); p.setAntiAlias(true); canvas->drawOval(r, p); } // return; dump_layers("outside layer alpha", canvas); // now apply an effect SkPaint paint; make_paint(&paint); r.set(0, 0, SkIntToScalar(100), SkIntToScalar(20)); // SkDebugf("--------- draw top grad\n"); canvas->drawRect(r, paint); SkMatrix m; SkShader* s = paint.getShader(); m.setScale(SK_Scalar1, -SK_Scalar1); m.postTranslate(0, SkIntToScalar(100)); s->setLocalMatrix(m); r.fTop = SkIntToScalar(80); r.fBottom = SkIntToScalar(100); // SkDebugf("--------- draw bot grad\n"); canvas->drawRect(r, paint); }
virtual void onDrawContent(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); if (false) { SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(50); paint.setTypeface(SkTypeface::CreateFromName("Arial Unicode MS", SkTypeface::kNormal)); SkSafeUnref(paint.getTypeface()); char buffer[10]; size_t len = SkUTF8_FromUnichar(0x8500, buffer); canvas->drawText(buffer, len, 40, 40, paint); return; } if (false) { SkPaint paint; paint.setAntiAlias(true); SkRect r0 = { 0, 0, 10.5f, 20 }; SkRect r1 = { 10.5f, 10, 20, 30 }; paint.setColor(SK_ColorRED); canvas->drawRect(r0, paint); paint.setColor(SK_ColorBLUE); canvas->drawRect(r1, paint); return; } const struct { SkXfermode::Mode fMode; const char* fLabel; } gModes[] = { { SkXfermode::kClear_Mode, "Clear" }, { SkXfermode::kSrc_Mode, "Src" }, { SkXfermode::kDst_Mode, "Dst" }, { SkXfermode::kSrcOver_Mode, "SrcOver" }, { SkXfermode::kDstOver_Mode, "DstOver" }, { SkXfermode::kSrcIn_Mode, "SrcIn" }, { SkXfermode::kDstIn_Mode, "DstIn" }, { SkXfermode::kSrcOut_Mode, "SrcOut" }, { SkXfermode::kDstOut_Mode, "DstOut" }, { SkXfermode::kSrcATop_Mode, "SrcATop" }, { SkXfermode::kDstATop_Mode, "DstATop" }, { SkXfermode::kXor_Mode, "Xor" }, { SkXfermode::kPlus_Mode, "Plus" }, /*{ SkXfermode::kModulate_Mode, "Modulate" }, { SkXfermode::kScreen_Mode, "Screen" }, { SkXfermode::kOverlay_Mode, "Overlay" }, { SkXfermode::kDarken_Mode, "Darken" }, { SkXfermode::kLighten_Mode, "Lighten" }, { SkXfermode::kColorDodge_Mode, "ColorDodge" }, { SkXfermode::kColorBurn_Mode, "ColorBurn" }, { SkXfermode::kHardLight_Mode, "HardLight" }, { SkXfermode::kSoftLight_Mode, "SoftLight" }, { SkXfermode::kDifference_Mode, "Difference" }, { SkXfermode::kExclusion_Mode, "Exclusion" },*/ }; const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkShader* s = SkShader::CreateBitmapShader(fBG, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); SkPaint labelP; labelP.setAntiAlias(true); labelP.setLCDRenderText(true); labelP.setTextAlign(SkPaint::kCenter_Align); setNamedTypeface(&labelP, "Menlo Regular"); const int W = 5; SkScalar x0 = 0; for (int twice = 0; twice < 2; twice++) { SkScalar x = x0, y = 0; for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); canvas->saveLayer(&r, NULL); draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop); canvas->restore(); r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); x += w + SkIntToScalar(10); if ((i % W) == W - 1) { x = x0; y += h + SkIntToScalar(30); } } x0 += SkIntToScalar(400); } s->unref(); }
static void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap, Float aAlpha = 1.0) { switch (aPattern.GetType()) { case PatternType::COLOR: { Color color = static_cast<const ColorPattern&>(aPattern).mColor; aPaint.setColor(ColorToSkColor(color, aAlpha)); break; } case PatternType::LINEAR_GRADIENT: { const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); if (stops->mCount >= 2) { SkPoint points[2]; points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y)); SkShader* shader = SkGradientShader::CreateLinear(points, &stops->mColors.front(), &stops->mPositions.front(), stops->mCount, mode); if (shader) { SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); shader->setLocalMatrix(mat); SkSafeUnref(aPaint.setShader(shader)); } } else { aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); } break; } case PatternType::RADIAL_GRADIENT: { const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); if (stops->mCount >= 2) { SkPoint points[2]; points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y)); SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0], SkFloatToScalar(pat.mRadius1), points[1], SkFloatToScalar(pat.mRadius2), &stops->mColors.front(), &stops->mPositions.front(), stops->mCount, mode); if (shader) { SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); shader->setLocalMatrix(mat); SkSafeUnref(aPaint.setShader(shader)); } } else { aPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); } break; } case PatternType::SURFACE: { const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern); aTmpBitmap = GetBitmapForSurface(pat.mSurface); const SkBitmap& bitmap = aTmpBitmap.mBitmap; SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode); SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode); SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); shader->setLocalMatrix(mat); SkSafeUnref(aPaint.setShader(shader)); if (pat.mFilter == Filter::POINT) { aPaint.setFilterLevel(SkPaint::kNone_FilterLevel); } break; } } }
bool SVGPaintServerGradient::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const { m_ownerElement->buildGradient(); RenderStyle* style = object->style(); bool isFilled = (type & ApplyToFillTargetType) && style->svgStyle()->hasFill(); bool isStroked = (type & ApplyToStrokeTargetType) && style->svgStyle()->hasStroke(); if(!gradientStops().size()) return false; if(gradientStops().size()==1) { context->setFillColor(gradientStops()[0].second); return true; } // Create a gradient builder helper to generate the data // we'll need to provide Skia SkiaGradientBuilder builder(gradientStops(), isFilled ? style->svgStyle()->fillOpacity() : style->svgStyle()->strokeOpacity()); SkShader::TileMode tile_mode; // Convert SVG spread modes to Skia tile modes switch(spreadMethod()) { default: case SPREADMETHOD_PAD: tile_mode = SkShader::kClamp_TileMode; break; case SPREADMETHOD_REFLECT: tile_mode = SkShader::kMirror_TileMode; break; case SPREADMETHOD_REPEAT: tile_mode = SkShader::kRepeat_TileMode; break; } SkShader* shader = NULL; SkMatrix matrix; // Calculate a matrix to transform a gradient to fit the bounding box if (boundingBoxMode()) { matrix.reset(); SkRect rc = context->getBoundingBoxForCurrentPath(true); matrix.preTranslate(rc.fLeft, rc.fTop); matrix.preScale(rc.width(), rc.height()); matrix.preConcat(gradientTransform()); } else matrix = gradientTransform(); if (this->type() == LinearGradientPaintServer) { const SVGPaintServerLinearGradient* linear = static_cast<const SVGPaintServerLinearGradient*>(this); SkPoint pts[2]; pts[0].fX = linear->gradientStart().x(); pts[0].fY = linear->gradientStart().y(); pts[1].fX = linear->gradientEnd().x(); pts[1].fY = linear->gradientEnd().y(); shader = SkGradientShader::CreateLinear(pts, builder.colors(), builder.pos(), builder.count(), tile_mode); } else if (this->type() == RadialGradientPaintServer) { const SVGPaintServerRadialGradient* radial = static_cast<const SVGPaintServerRadialGradient*>(this); SkPoint center; SkScalar radius; center.fX = radial->gradientCenter().x(); center.fY = radial->gradientCenter().y(); radius = radial->gradientRadius(); shader = SkGradientShader::CreateRadial( center, radius, builder.colors(), builder.pos(), builder.count(), tile_mode); } else { return false; } if (isPaintingText) { if (isFilled) { context->setTextDrawingMode(cTextFill); } if (isStroked) { context->setTextDrawingMode(cTextStroke); } } if (isStroked) { applyStrokeStyleToContext(context, style, object); } if (shader) { shader->setLocalMatrix(matrix); context->platformContext()->setGradient(shader); return true; } return false; }