Example #1
0
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));
}
Example #3
0
// TODO(ccameron): ImagePattern should not draw to a globally set color space.
// https://crbug.com/672306
ImagePattern::ImagePattern(PassRefPtr<Image> image, RepeatMode repeatMode)
    : Pattern(repeatMode),
      m_tileImage(image->imageForCurrentFrame(
          ColorBehavior::transformToGlobalTarget())) {
  m_previousLocalMatrix.setIdentity();
  if (m_tileImage) {
    // TODO(fmalita): mechanism to extract the actual SkImageInfo from an
    // SkImage?
    const SkImageInfo info = SkImageInfo::MakeN32Premul(
        m_tileImage->width() + (isRepeatX() ? 0 : 2),
        m_tileImage->height() + (isRepeatY() ? 0 : 2));
    adjustExternalMemoryAllocated(info.getSafeSize(info.minRowBytes()));
  }
}