blob: e215eb305d3e97bf9d0f0abab8a2b914f6487294 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/graphics/PlaceholderImage.h"
#include "platform/geometry/FloatRect.h"
#include "platform/geometry/IntPoint.h"
#include "platform/geometry/IntRect.h"
#include "platform/graphics/BitmapImage.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageObserver.h"
#include "platform/graphics/paint/PaintCanvas.h"
#include "platform/graphics/paint/PaintFlags.h"
#include "platform/graphics/paint/PaintRecord.h"
#include "platform/graphics/paint/PaintRecorder.h"
#include "platform/wtf/StdLibExtras.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSize.h"
namespace blink {
PlaceholderImage::PlaceholderImage(ImageObserver* observer, const IntSize& size)
: Image(observer), size_(size) {}
PlaceholderImage::~PlaceholderImage() {}
sk_sp<SkImage> PlaceholderImage::ImageForCurrentFrame() {
if (image_for_current_frame_)
return image_for_current_frame_;
const FloatRect dest_rect(0.0f, 0.0f, static_cast<float>(size_.Width()),
static_cast<float>(size_.Height()));
PaintRecorder paint_recorder;
Draw(paint_recorder.beginRecording(dest_rect), PaintFlags(), dest_rect,
dest_rect, kDoNotRespectImageOrientation, kClampImageToSourceRect);
image_for_current_frame_ = SkImage::MakeFromPicture(
ToSkPicture(paint_recorder.finishRecordingAsPicture(), dest_rect),
SkISize::Make(size_.Width(), size_.Height()), nullptr, nullptr,
SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
return image_for_current_frame_;
}
void PlaceholderImage::Draw(PaintCanvas* canvas,
const PaintFlags& base_flags,
const FloatRect& dest_rect,
const FloatRect& src_rect,
RespectImageOrientationEnum respect_orientation,
ImageClampingMode image_clamping_mode) {
if (!src_rect.Intersects(FloatRect(0.0f, 0.0f,
static_cast<float>(size_.Width()),
static_cast<float>(size_.Height())))) {
return;
}
// Placeholder image visual specifications:
// https://docs.google.com/document/d/1BHeA1azbgCdZgCnr16VN2g7A9MHPQ_dwKn5szh8evMQ/edit
PaintFlags flags(base_flags);
flags.setStyle(PaintFlags::kFill_Style);
flags.setColor(SkColorSetARGB(0x80, 0xD9, 0xD9, 0xD9));
canvas->drawRect(dest_rect, flags);
constexpr int kIconWidth = 24;
constexpr int kIconHeight = 24;
constexpr int kIconPaddingX = 8;
constexpr int kIconPaddingY = 5;
if (dest_rect.Width() < kIconWidth + 2 * kIconPaddingX ||
dest_rect.Height() < kIconHeight + 2 * kIconPaddingY) {
return;
}
DEFINE_STATIC_REF(Image, icon_image,
(Image::LoadPlatformResource("placeholderIcon")));
DCHECK(!icon_image->IsNull());
FloatRect icon_dest_rect(
dest_rect.X() + (dest_rect.Width() - kIconWidth) / 2.0f,
dest_rect.Y() + (dest_rect.Height() - kIconHeight) / 2.0f, kIconWidth,
kIconHeight);
// Note that the |icon_image| is not scaled according to dest_rect / src_rect,
// and is always drawn at the same size. This is so that placeholder icons are
// visible (e.g. when replacing a large image that's scaled down to a small
// area) and so that all placeholder images on the same page look consistent.
canvas->drawImageRect(icon_image->PaintImageForCurrentFrame(),
IntRect(IntPoint::Zero(), icon_image->Size()),
icon_dest_rect, &base_flags,
PaintCanvas::kFast_SrcRectConstraint);
}
void PlaceholderImage::DrawPattern(GraphicsContext& context,
const FloatRect& src_rect,
const FloatSize& scale,
const FloatPoint& phase,
SkBlendMode mode,
const FloatRect& dest_rect,
const FloatSize& repeat_spacing) {
DCHECK(context.Canvas());
PaintFlags flags = context.FillFlags();
flags.setBlendMode(mode);
// Ignore the pattern specifications and just draw a single placeholder image
// over the whole |dest_rect|. This is done in order to prevent repeated icons
// from cluttering tiled background images.
Draw(context.Canvas(), flags, dest_rect, src_rect,
kDoNotRespectImageOrientation, kClampImageToSourceRect);
}
void PlaceholderImage::DestroyDecodedData() {
image_for_current_frame_.reset();
}
} // namespace blink