| // Copyright 2013 The Flutter 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 <vector> |
| |
| #include "impeller/display_list/nine_patch_converter.h" |
| |
| namespace impeller { |
| |
| NinePatchConverter::NinePatchConverter() = default; |
| |
| NinePatchConverter::~NinePatchConverter() = default; |
| |
| std::vector<double> NinePatchConverter::InitSlices(double img0, |
| double imgC0, |
| double imgC1, |
| double img1, |
| double dst0, |
| double dst1) { |
| auto imageDim = img1 - img0; |
| auto destDim = dst1 - dst0; |
| |
| if (imageDim == destDim) { |
| // If the src and dest are the same size then we do not need scaling |
| // We return 4 values for a single slice |
| return {img0, dst0, img1, dst1}; |
| } |
| |
| auto edge0Dim = imgC0 - img0; |
| auto edge1Dim = img1 - imgC1; |
| auto edgesDim = edge0Dim + edge1Dim; |
| |
| if (edgesDim >= destDim) { |
| // the center portion has disappeared, leaving only the edges to scale to a |
| // common center position in the destination this produces only 2 slices |
| // which is 8 values |
| auto dstC = dst0 + destDim * edge0Dim / edgesDim; |
| // clang-format off |
| return { |
| img0, dst0, imgC0, dstC, |
| imgC1, dstC, img1, dst1, |
| }; |
| // clang-format on |
| } |
| |
| // center portion is nonEmpty and only that part is scaled |
| // we need 3 slices which is 12 values |
| auto dstC0 = dst0 + edge0Dim; |
| auto dstC1 = dst1 - edge1Dim; |
| // clang-format off |
| return { |
| img0, dst0, imgC0, dstC0, |
| imgC0, dstC0, imgC1, dstC1, |
| imgC1, dstC1, img1, dst1, |
| }; |
| // clang-format on |
| } |
| |
| void NinePatchConverter::DrawNinePatch(const std::shared_ptr<Image>& image, |
| Rect center, |
| Rect dst, |
| const SamplerDescriptor& sampler, |
| Canvas* canvas, |
| Paint* paint) { |
| if (dst.IsEmpty()) { |
| return; |
| } |
| auto image_size = image->GetSize(); |
| auto hSlices = InitSlices(0, center.GetLeft(), center.GetRight(), |
| image_size.width, dst.GetLeft(), dst.GetRight()); |
| auto vSlices = InitSlices(0, center.GetTop(), center.GetBottom(), |
| image_size.height, dst.GetTop(), dst.GetBottom()); |
| |
| for (size_t yi = 0; yi < vSlices.size(); yi += 4) { |
| auto srcY0 = vSlices[yi]; |
| auto dstY0 = vSlices[yi + 1]; |
| auto srcY1 = vSlices[yi + 2]; |
| auto dstY1 = vSlices[yi + 3]; |
| for (size_t xi = 0; xi < hSlices.size(); xi += 4) { |
| auto srcX0 = hSlices[xi]; |
| auto dstX0 = hSlices[xi + 1]; |
| auto srcX1 = hSlices[xi + 2]; |
| auto dstX1 = hSlices[xi + 3]; |
| // TODO(jonahwilliams): consider converting this into a single call to |
| // DrawImageAtlas. |
| canvas->DrawImageRect(image, Rect::MakeLTRB(srcX0, srcY0, srcX1, srcY1), |
| Rect::MakeLTRB(dstX0, dstY0, dstX1, dstY1), *paint, |
| sampler); |
| } |
| } |
| } |
| |
| } // namespace impeller |