| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/gfx/nine_image_painter.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 | |
| 9 #include "third_party/skia/include/core/SkPaint.h" | |
| 10 #include "third_party/skia/include/core/SkRect.h" | |
| 11 #include "third_party/skia/include/core/SkScalar.h" | |
| 12 #include "ui/gfx/canvas.h" | |
| 13 #include "ui/gfx/geometry/rect_conversions.h" | |
| 14 #include "ui/gfx/geometry/safe_integer_conversions.h" | |
| 15 #include "ui/gfx/image/image_skia_operations.h" | |
| 16 #include "ui/gfx/insets.h" | |
| 17 #include "ui/gfx/rect.h" | |
| 18 #include "ui/gfx/scoped_canvas.h" | |
| 19 #include "ui/gfx/skia_util.h" | |
| 20 | |
| 21 namespace gfx { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // The following functions width and height of the image in pixels for the | |
| 26 // scale factor in the Canvas. | |
| 27 int ImageWidthInPixels(const ImageSkia& i, Canvas* c) { | |
| 28 return i.GetRepresentation(c->image_scale()).pixel_width(); | |
| 29 } | |
| 30 | |
| 31 int ImageHeightInPixels(const ImageSkia& i, Canvas* c) { | |
| 32 return i.GetRepresentation(c->image_scale()).pixel_height(); | |
| 33 } | |
| 34 | |
| 35 // Stretches the given image over the specified canvas area. | |
| 36 void Fill(Canvas* c, | |
| 37 const ImageSkia& i, | |
| 38 int x, | |
| 39 int y, | |
| 40 int w, | |
| 41 int h, | |
| 42 const SkPaint& paint) { | |
| 43 c->DrawImageIntInPixel(i, 0, 0, ImageWidthInPixels(i, c), | |
| 44 ImageHeightInPixels(i, c), x, y, w, h, false, paint); | |
| 45 } | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) { | |
| 50 DCHECK_EQ(arraysize(images_), images.size()); | |
| 51 for (size_t i = 0; i < arraysize(images_); ++i) | |
| 52 images_[i] = images[i]; | |
| 53 } | |
| 54 | |
| 55 NineImagePainter::NineImagePainter(const ImageSkia& image, | |
| 56 const Insets& insets) { | |
| 57 DCHECK_GE(image.width(), insets.width()); | |
| 58 DCHECK_GE(image.height(), insets.height()); | |
| 59 | |
| 60 // Extract subsets of the original image to match the |images_| format. | |
| 61 const int x[] = | |
| 62 { 0, insets.left(), image.width() - insets.right(), image.width() }; | |
| 63 const int y[] = | |
| 64 { 0, insets.top(), image.height() - insets.bottom(), image.height() }; | |
| 65 | |
| 66 for (size_t j = 0; j < 3; ++j) { | |
| 67 for (size_t i = 0; i < 3; ++i) { | |
| 68 images_[i + j * 3] = ImageSkiaOperations::ExtractSubset(image, | |
| 69 Rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j])); | |
| 70 } | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 NineImagePainter::~NineImagePainter() { | |
| 75 } | |
| 76 | |
| 77 bool NineImagePainter::IsEmpty() const { | |
| 78 return images_[0].isNull(); | |
| 79 } | |
| 80 | |
| 81 Size NineImagePainter::GetMinimumSize() const { | |
| 82 return IsEmpty() ? Size() : Size( | |
| 83 images_[0].width() + images_[1].width() + images_[2].width(), | |
| 84 images_[0].height() + images_[3].height() + images_[6].height()); | |
| 85 } | |
| 86 | |
| 87 void NineImagePainter::Paint(Canvas* canvas, const Rect& bounds) { | |
| 88 // When no alpha value is specified, use default value of 100% opacity. | |
| 89 Paint(canvas, bounds, std::numeric_limits<uint8>::max()); | |
| 90 } | |
| 91 | |
| 92 void NineImagePainter::Paint(Canvas* canvas, | |
| 93 const Rect& bounds, | |
| 94 const uint8 alpha) { | |
| 95 if (IsEmpty()) | |
| 96 return; | |
| 97 | |
| 98 ScopedCanvas scoped_canvas(canvas); | |
| 99 canvas->Translate(bounds.OffsetFromOrigin()); | |
| 100 | |
| 101 // Get the current transform from the canvas and apply it to the logical | |
| 102 // bounds passed in. This will give us the pixel bounds which can be used | |
| 103 // to draw the images at the correct locations. | |
| 104 // We should not scale the bounds by the canvas->image_scale() as that can be | |
| 105 // different from the real scale in the canvas transform. | |
| 106 SkRect bounds_in_pixels_f; | |
| 107 if (!canvas->sk_canvas()->getTotalMatrix().mapRect( | |
| 108 &bounds_in_pixels_f, RectToSkRect(gfx::Rect(bounds.size())))) | |
| 109 return; // Invalid transform. | |
| 110 | |
| 111 SkIRect bounds_in_pixels; | |
| 112 bounds_in_pixels_f.dround(&bounds_in_pixels); | |
| 113 | |
| 114 SkMatrix matrix = canvas->sk_canvas()->getTotalMatrix(); | |
| 115 matrix.setTranslateX(SkIntToScalar(bounds_in_pixels.x())); | |
| 116 matrix.setTranslateY(SkIntToScalar(bounds_in_pixels.y())); | |
| 117 canvas->sk_canvas()->setMatrix(matrix); | |
| 118 | |
| 119 const int width_in_pixels = bounds_in_pixels.width(); | |
| 120 const int height_in_pixels = bounds_in_pixels.height(); | |
| 121 | |
| 122 // In case the corners and edges don't all have the same width/height, we draw | |
| 123 // the center first, and extend it out in all directions to the edges of the | |
| 124 // images with the smallest widths/heights. This way there will be no | |
| 125 // unpainted areas, though some corners or edges might overlap the center. | |
| 126 int i0w = ImageWidthInPixels(images_[0], canvas); | |
| 127 int i2w = ImageWidthInPixels(images_[2], canvas); | |
| 128 int i3w = ImageWidthInPixels(images_[3], canvas); | |
| 129 int i5w = ImageWidthInPixels(images_[5], canvas); | |
| 130 int i6w = ImageWidthInPixels(images_[6], canvas); | |
| 131 int i8w = ImageWidthInPixels(images_[8], canvas); | |
| 132 | |
| 133 int i4x = std::min(std::min(i0w, i3w), i6w); | |
| 134 int i4w = width_in_pixels - i4x - std::min(std::min(i2w, i5w), i8w); | |
| 135 | |
| 136 int i0h = ImageHeightInPixels(images_[0], canvas); | |
| 137 int i1h = ImageHeightInPixels(images_[1], canvas); | |
| 138 int i2h = ImageHeightInPixels(images_[2], canvas); | |
| 139 int i6h = ImageHeightInPixels(images_[6], canvas); | |
| 140 int i7h = ImageHeightInPixels(images_[7], canvas); | |
| 141 int i8h = ImageHeightInPixels(images_[8], canvas); | |
| 142 | |
| 143 int i4y = std::min(std::min(i0h, i1h), i2h); | |
| 144 int i4h = height_in_pixels - i4y - std::min(std::min(i6h, i7h), i8h); | |
| 145 | |
| 146 SkPaint paint; | |
| 147 paint.setAlpha(alpha); | |
| 148 | |
| 149 if (!images_[4].isNull()) | |
| 150 Fill(canvas, images_[4], i4x, i4y, i4w, i4h, paint); | |
| 151 canvas->DrawImageIntInPixel(images_[0], 0, 0, i0w, i0h, | |
| 152 0, 0, i0w, i0h, false, paint); | |
| 153 Fill(canvas, images_[1], i0w, 0, width_in_pixels - i0w - i2w, i1h, paint); | |
| 154 canvas->DrawImageIntInPixel(images_[2], 0, 0, i2w, i2h, width_in_pixels - i2w, | |
| 155 0, i2w, i2h, false, paint); | |
| 156 Fill(canvas, images_[3], 0, i0h, i3w, height_in_pixels - i0h - i6h, paint); | |
| 157 Fill(canvas, images_[5], width_in_pixels - i5w, i2h, i5w, | |
| 158 height_in_pixels - i2h - i8h, paint); | |
| 159 canvas->DrawImageIntInPixel(images_[6], 0, 0, i6w, i6h, 0, | |
| 160 height_in_pixels - i6h, i6w, i6h, false, paint); | |
| 161 Fill(canvas, images_[7], i6w, height_in_pixels - i7h, | |
| 162 width_in_pixels - i6w - i8w, i7h, paint); | |
| 163 canvas->DrawImageIntInPixel(images_[8], 0, 0, i8w, i8h, width_in_pixels - i8w, | |
| 164 height_in_pixels - i8h, i8w, i8h, false, paint); | |
| 165 } | |
| 166 | |
| 167 } // namespace gfx | |
| OLD | NEW |