15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/nine_image_painter.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include <limits> 823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h" 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "third_party/skia/include/core/SkRect.h" 11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "third_party/skia/include/core/SkScalar.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/canvas.h" 13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/gfx/geometry/rect_conversions.h" 14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/gfx/geometry/safe_integer_conversions.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/insets.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/rect.h" 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/scoped_canvas.h" 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gfx/skia_util.h" 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gfx { 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace { 2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// The following functions width and height of the image in pixels for the 26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// scale factor in the Canvas. 27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)int ImageWidthInPixels(const ImageSkia& i, Canvas* c) { 28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return i.GetRepresentation(c->image_scale()).pixel_width(); 29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)int ImageHeightInPixels(const ImageSkia& i, Canvas* c) { 32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return i.GetRepresentation(c->image_scale()).pixel_height(); 33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Stretches the given image over the specified canvas area. 3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void Fill(Canvas* c, 3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const ImageSkia& i, 3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int x, 3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int y, 4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int w, 4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int h, 4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const SkPaint& paint) { 43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) c->DrawImageIntInPixel(i, 0, 0, ImageWidthInPixels(i, c), 44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ImageHeightInPixels(i, c), x, y, w, h, false, paint); 4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} // namespace 4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) { 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_EQ(arraysize(images_), images.size()); 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < arraysize(images_); ++i) 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) images_[i] = images[i]; 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NineImagePainter::NineImagePainter(const ImageSkia& image, 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const Insets& insets) { 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_GE(image.width(), insets.width()); 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_GE(image.height(), insets.height()); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Extract subsets of the original image to match the |images_| format. 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int x[] = 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 0, insets.left(), image.width() - insets.right(), image.width() }; 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int y[] = 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 0, insets.top(), image.height() - insets.bottom(), image.height() }; 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t j = 0; j < 3; ++j) { 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < 3; ++i) { 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) images_[i + j * 3] = ImageSkiaOperations::ExtractSubset(image, 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j])); 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NineImagePainter::~NineImagePainter() { 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool NineImagePainter::IsEmpty() const { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return images_[0].isNull(); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Size NineImagePainter::GetMinimumSize() const { 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return IsEmpty() ? Size() : Size( 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) images_[0].width() + images_[1].width() + images_[2].width(), 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) images_[0].height() + images_[3].height() + images_[6].height()); 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NineImagePainter::Paint(Canvas* canvas, const Rect& bounds) { 8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // When no alpha value is specified, use default value of 100% opacity. 8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) Paint(canvas, bounds, std::numeric_limits<uint8>::max()); 9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void NineImagePainter::Paint(Canvas* canvas, 9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const Rect& bounds, 9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const uint8 alpha) { 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (IsEmpty()) 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedCanvas scoped_canvas(canvas); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) canvas->Translate(bounds.OffsetFromOrigin()); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) SkPaint paint; 10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) paint.setAlpha(alpha); 10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Get the current transform from the canvas and apply it to the logical 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // bounds passed in. This will give us the pixel bounds which can be used 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to draw the images at the correct locations. 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // We should not scale the bounds by the canvas->image_scale() as that can be 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // different from the real scale in the canvas transform. 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SkMatrix matrix = canvas->sk_canvas()->getTotalMatrix(); 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SkRect scaled_rect; 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) matrix.mapRect(&scaled_rect, RectToSkRect(bounds)); 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int scaled_width = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.width())); 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int scaled_height = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.height())); 115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In case the corners and edges don't all have the same width/height, we draw 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the center first, and extend it out in all directions to the edges of the 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // images with the smallest widths/heights. This way there will be no 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // unpainted areas, though some corners or edges might overlap the center. 120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i0w = ImageWidthInPixels(images_[0], canvas); 121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i2w = ImageWidthInPixels(images_[2], canvas); 122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i3w = ImageWidthInPixels(images_[3], canvas); 123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i5w = ImageWidthInPixels(images_[5], canvas); 124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i6w = ImageWidthInPixels(images_[6], canvas); 125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i8w = ImageWidthInPixels(images_[8], canvas); 126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int i4x = std::min(std::min(i0w, i3w), i6w); 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int i4w = scaled_width - i4x - std::min(std::min(i2w, i5w), i8w); 129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i0h = ImageHeightInPixels(images_[0], canvas); 131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i1h = ImageHeightInPixels(images_[1], canvas); 132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i2h = ImageHeightInPixels(images_[2], canvas); 133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i6h = ImageHeightInPixels(images_[6], canvas); 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i7h = ImageHeightInPixels(images_[7], canvas); 135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int i8h = ImageHeightInPixels(images_[8], canvas); 136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int i4y = std::min(std::min(i0h, i1h), i2h); 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int i4h = scaled_height - i4y - std::min(std::min(i6h, i7h), i8h); 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!images_[4].isNull()) 14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) Fill(canvas, images_[4], i4x, i4y, i4w, i4h, paint); 141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) canvas->DrawImageIntInPixel(images_[0], 0, 0, i0w, i0h, 142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 0, 0, i0w, i0h, false, paint); 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Fill(canvas, images_[1], i0w, 0, scaled_width - i0w - i2w, i1h, paint); 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) canvas->DrawImageIntInPixel(images_[2], 0, 0, i2w, i2h, scaled_width - i2w, 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 0, i2w, i2h, false, paint); 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Fill(canvas, images_[3], 0, i0h, i3w, scaled_height - i0h - i6h, paint); 147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Fill(canvas, images_[5], scaled_width - i5w, i2h, i5w, 148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scaled_height - i2h - i8h, paint); 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) canvas->DrawImageIntInPixel(images_[6], 0, 0, i6w, i6h, 0, 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scaled_height - i6h, i6w, i6h, false, paint); 151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Fill(canvas, images_[7], i6w, scaled_height - i7h, scaled_width - i6w - i8w, 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) i7h, paint); 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) canvas->DrawImageIntInPixel(images_[8], 0, 0, i8w, i8h, scaled_width - i8w, 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scaled_height - i8h, i8w, i8h, false, paint); 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace gfx 158