Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87f82bb9 authored by Jeremy Meyer's avatar Jeremy Meyer Committed by Android (Google) Code Review
Browse files

Merge "Revert^2 "Move some image/9patch code to androidfw"" into main

parents fb9e3cfe b4f83ff6
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -63,15 +63,21 @@ cc_library {
        "AssetsProvider.cpp",
        "AttributeResolution.cpp",
        "BigBuffer.cpp",
        "BigBufferStream.cpp",
        "ChunkIterator.cpp",
        "ConfigDescription.cpp",
        "FileStream.cpp",
        "Idmap.cpp",
        "LoadedArsc.cpp",
        "Locale.cpp",
        "LocaleData.cpp",
        "misc.cpp",
        "NinePatch.cpp",
        "ObbFile.cpp",
        "PosixUtils.cpp",
        "Png.cpp",
        "PngChunkFilter.cpp",
        "PngCrunch.cpp",
        "ResourceTimer.cpp",
        "ResourceTypes.cpp",
        "ResourceUtils.cpp",
@@ -84,7 +90,10 @@ cc_library {
    ],
    export_include_dirs: ["include"],
    export_shared_lib_headers: ["libz"],
    static_libs: ["libincfs-utils"],
    static_libs: [
        "libincfs-utils",
        "libpng",
    ],
    whole_static_libs: [
        "libandroidfw_pathutils",
        "libincfs-utils",
@@ -198,9 +207,11 @@ cc_test {
        "tests/ConfigDescription_test.cpp",
        "tests/ConfigLocale_test.cpp",
        "tests/DynamicRefTable_test.cpp",
        "tests/FileStream_test.cpp",
        "tests/Idmap_test.cpp",
        "tests/LoadedArsc_test.cpp",
        "tests/Locale_test.cpp",
        "tests/NinePatch_test.cpp",
        "tests/ResourceTimer_test.cpp",
        "tests/ResourceUtils_test.cpp",
        "tests/ResTable_test.cpp",
+33 −5
Original line number Diff line number Diff line
@@ -14,10 +14,11 @@
 * limitations under the License.
 */

#include "io/BigBufferStream.h"
#include "androidfw/BigBufferStream.h"

namespace aapt {
namespace io {
#include <algorithm>

namespace android {

//
// BigBufferInputStream
@@ -76,6 +77,34 @@ size_t BigBufferInputStream::TotalSize() const {
  return buffer_->size();
}

bool BigBufferInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
  if (byte_count == 0) {
    return true;
  }
  if (offset < 0) {
    return false;
  }
  if (offset > std::numeric_limits<off64_t>::max() - byte_count) {
    return false;
  }
  if (offset + byte_count > buffer_->size()) {
    return false;
  }
  auto p = reinterpret_cast<uint8_t*>(data);
  for (auto iter = buffer_->begin(); iter != buffer_->end() && byte_count > 0; ++iter) {
    if (offset < iter->size) {
      size_t to_read = std::min(byte_count, (size_t)(iter->size - offset));
      memcpy(p, iter->buffer.get() + offset, to_read);
      byte_count -= to_read;
      p += to_read;
      offset = 0;
    } else {
      offset -= iter->size;
    }
  }
  return byte_count == 0;
}

//
// BigBufferOutputStream
//
@@ -97,5 +126,4 @@ bool BigBufferOutputStream::HadError() const {
  return false;
}

}  // namespace io
}  // namespace aapt
}  // namespace android
+7 −5
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#include "io/FileStream.h"
#include "androidfw/FileStream.h"

#include <errno.h>   // for errno
#include <fcntl.h>   // for O_RDONLY
@@ -34,8 +34,7 @@
using ::android::base::SystemErrorCodeToString;
using ::android::base::unique_fd;

namespace aapt {
namespace io {
namespace android {

FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
    : buffer_capacity_(buffer_capacity) {
@@ -108,6 +107,10 @@ std::string FileInputStream::GetError() const {
  return error_;
}

bool FileInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) {
  return base::ReadFullyAtOffset(fd_, data, byte_count, offset);
}

FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
    : buffer_capacity_(buffer_capacity) {
  int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
@@ -199,5 +202,4 @@ std::string FileOutputStream::GetError() const {
  return error_;
}

}  // namespace io
}  // namespace aapt
}  // namespace android
+84 −100
Original line number Diff line number Diff line
@@ -14,20 +14,17 @@
 * limitations under the License.
 */

#include "compile/Image.h"

#include <sstream>
#include <string>
#include <vector>

#include "androidfw/Image.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"

#include "util/Util.h"

using android::StringPiece;

namespace aapt {
namespace android {

// Colors in the format 0xAARRGGBB (the way 9-patch expects it).
constexpr static const uint32_t kColorOpaqueWhite = 0xffffffffu;
@@ -90,10 +87,8 @@ class ColorValidator {
// };
//
template <typename ImageLine>
static bool FillRanges(const ImageLine* image_line,
                       const ColorValidator* color_validator,
                       std::vector<Range>* primary_ranges,
                       std::vector<Range>* secondary_ranges,
static bool FillRanges(const ImageLine* image_line, const ColorValidator* color_validator,
                       std::vector<Range>* primary_ranges, std::vector<Range>* secondary_ranges,
                       std::string* out_err) {
  const int32_t length = image_line->GetLength();

@@ -133,11 +128,13 @@ static bool FillRanges(const ImageLine* image_line,
 */
class HorizontalImageLine {
 public:
  explicit HorizontalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
                               int32_t length)
      : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {}
  explicit HorizontalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t length)
      : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {
  }

  inline int32_t GetLength() const { return length_; }
  inline int32_t GetLength() const {
    return length_;
  }

  inline uint32_t GetColor(int32_t idx) const {
    return NinePatch::PackRGBA(rows_[yoffset_] + (idx + xoffset_) * 4);
@@ -156,11 +153,13 @@ class HorizontalImageLine {
 */
class VerticalImageLine {
 public:
  explicit VerticalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
                             int32_t length)
      : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {}
  explicit VerticalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t length)
      : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {
  }

  inline int32_t GetLength() const { return length_; }
  inline int32_t GetLength() const {
    return length_;
  }

  inline uint32_t GetColor(int32_t idx) const {
    return NinePatch::PackRGBA(rows_[yoffset_ + idx] + (xoffset_ * 4));
@@ -175,20 +174,22 @@ class VerticalImageLine {

class DiagonalImageLine {
 public:
  explicit DiagonalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset,
                             int32_t xstep, int32_t ystep, int32_t length)
  explicit DiagonalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t xstep,
                             int32_t ystep, int32_t length)
      : rows_(rows),
        xoffset_(xoffset),
        yoffset_(yoffset),
        xstep_(xstep),
        ystep_(ystep),
        length_(length) {}
        length_(length) {
  }

  inline int32_t GetLength() const { return length_; }
  inline int32_t GetLength() const {
    return length_;
  }

  inline uint32_t GetColor(int32_t idx) const {
    return NinePatch::PackRGBA(rows_[yoffset_ + (idx * ystep_)] +
                               ((idx + xoffset_) * xstep_) * 4);
    return NinePatch::PackRGBA(rows_[yoffset_ + (idx * ystep_)] + ((idx + xoffset_) * xstep_) * 4);
  }

 private:
@@ -243,8 +244,7 @@ static bool PopulateBounds(const std::vector<Range>& padding,

  if (layout_bounds.size() > 2) {
    std::stringstream err_stream;
    err_stream << "too many layout bounds sections on " << edge_name
               << " border";
    err_stream << "too many layout bounds sections on " << edge_name << " border";
    *out_err = err_stream.str();
    return false;
  }
@@ -258,8 +258,7 @@ static bool PopulateBounds(const std::vector<Range>& padding,
    // end at length.
    if (range.start != 0 && range.end != length) {
      std::stringstream err_stream;
      err_stream << "layout bounds on " << edge_name
                 << " border must start at edge";
      err_stream << "layout bounds on " << edge_name << " border must start at edge";
      *out_err = err_stream.str();
      return false;
    }
@@ -269,8 +268,7 @@ static bool PopulateBounds(const std::vector<Range>& padding,
      const Range& range = layout_bounds.back();
      if (range.end != length) {
        std::stringstream err_stream;
        err_stream << "layout bounds on " << edge_name
                   << " border must start at edge";
        err_stream << "layout bounds on " << edge_name << " border must start at edge";
        *out_err = err_stream.str();
        return false;
      }
@@ -280,8 +278,7 @@ static bool PopulateBounds(const std::vector<Range>& padding,
  return true;
}

static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions,
                                     int32_t length) {
static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions, int32_t length) {
  if (stretch_regions.size() == 0) {
    return 0;
  }
@@ -299,8 +296,7 @@ static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions,

static uint32_t GetRegionColor(uint8_t** rows, const Bounds& region) {
  // Sample the first pixel to compare against.
  const uint32_t expected_color =
      NinePatch::PackRGBA(rows[region.top] + region.left * 4);
  const uint32_t expected_color = NinePatch::PackRGBA(rows[region.top] + region.left * 4);
  for (int32_t y = region.top; y < region.bottom; y++) {
    const uint8_t* row = rows[y];
    for (int32_t x = region.left; x < region.right; x++) {
@@ -336,10 +332,11 @@ static uint32_t GetRegionColor(uint8_t** rows, const Bounds& region) {
// the indices must be offset by 1.
//
// width and height also include the 9-patch 1px border.
static void CalculateRegionColors(
    uint8_t** rows, const std::vector<Range>& horizontal_stretch_regions,
    const std::vector<Range>& vertical_stretch_regions, const int32_t width,
    const int32_t height, std::vector<uint32_t>* out_colors) {
static void CalculateRegionColors(uint8_t** rows,
                                  const std::vector<Range>& horizontal_stretch_regions,
                                  const std::vector<Range>& vertical_stretch_regions,
                                  const int32_t width, const int32_t height,
                                  std::vector<uint32_t>* out_colors) {
  int32_t next_top = 0;
  Bounds bounds;
  auto row_iter = vertical_stretch_regions.begin();
@@ -401,8 +398,7 @@ static void CalculateRegionColors(
// alpha value begins
// (on both sides).
template <typename ImageLine>
static void FindOutlineInsets(const ImageLine* image_line, int32_t* out_start,
                              int32_t* out_end) {
static void FindOutlineInsets(const ImageLine* image_line, int32_t* out_start, int32_t* out_end) {
  *out_start = 0;
  *out_end = 0;

@@ -455,10 +451,8 @@ uint32_t NinePatch::PackRGBA(const uint8_t* pixel) {
  return (pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
}

std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
                                             const int32_t width,
                                             const int32_t height,
                                             std::string* out_err) {
std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, const int32_t width,
                                             const int32_t height, std::string* out_err) {
  if (width < 3 || height < 3) {
    *out_err = "image must be at least 3x3 (1x1 image with 1 pixel border)";
    return {};
@@ -472,12 +466,11 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
  std::unique_ptr<ColorValidator> color_validator;

  if (rows[0][3] == 0) {
    color_validator = util::make_unique<TransparentNeutralColorValidator>();
    color_validator = std::make_unique<TransparentNeutralColorValidator>();
  } else if (PackRGBA(rows[0]) == kColorOpaqueWhite) {
    color_validator = util::make_unique<WhiteNeutralColorValidator>();
    color_validator = std::make_unique<WhiteNeutralColorValidator>();
  } else {
    *out_err =
        "top-left corner pixel must be either opaque white or transparent";
    *out_err = "top-left corner pixel must be either opaque white or transparent";
    return {};
  }

@@ -485,9 +478,8 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
  auto nine_patch = std::unique_ptr<NinePatch>(new NinePatch());

  HorizontalImageLine top_row(rows, 0, 0, width);
  if (!FillRanges(&top_row, color_validator.get(),
                  &nine_patch->horizontal_stretch_regions, &unexpected_ranges,
                  out_err)) {
  if (!FillRanges(&top_row, color_validator.get(), &nine_patch->horizontal_stretch_regions,
                  &unexpected_ranges, out_err)) {
    return {};
  }

@@ -501,9 +493,8 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
  }

  VerticalImageLine left_col(rows, 0, 0, height);
  if (!FillRanges(&left_col, color_validator.get(),
                  &nine_patch->vertical_stretch_regions, &unexpected_ranges,
                  out_err)) {
  if (!FillRanges(&left_col, color_validator.get(), &nine_patch->vertical_stretch_regions,
                  &unexpected_ranges, out_err)) {
    return {};
  }

@@ -522,32 +513,28 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,
  }

  if (!PopulateBounds(horizontal_padding, horizontal_layout_bounds,
                      nine_patch->horizontal_stretch_regions, width - 2,
                      &nine_patch->padding.left, &nine_patch->padding.right,
                      &nine_patch->layout_bounds.left,
                      nine_patch->horizontal_stretch_regions, width - 2, &nine_patch->padding.left,
                      &nine_patch->padding.right, &nine_patch->layout_bounds.left,
                      &nine_patch->layout_bounds.right, "bottom", out_err)) {
    return {};
  }

  VerticalImageLine right_col(rows, width - 1, 0, height);
  if (!FillRanges(&right_col, color_validator.get(), &vertical_padding,
                  &vertical_layout_bounds, out_err)) {
  if (!FillRanges(&right_col, color_validator.get(), &vertical_padding, &vertical_layout_bounds,
                  out_err)) {
    return {};
  }

  if (!PopulateBounds(vertical_padding, vertical_layout_bounds,
                      nine_patch->vertical_stretch_regions, height - 2,
                      &nine_patch->padding.top, &nine_patch->padding.bottom,
                      &nine_patch->layout_bounds.top,
                      nine_patch->vertical_stretch_regions, height - 2, &nine_patch->padding.top,
                      &nine_patch->padding.bottom, &nine_patch->layout_bounds.top,
                      &nine_patch->layout_bounds.bottom, "right", out_err)) {
    return {};
  }

  // Fill the region colors of the 9-patch.
  const int32_t num_rows =
      CalculateSegmentCount(nine_patch->horizontal_stretch_regions, width - 2);
  const int32_t num_cols =
      CalculateSegmentCount(nine_patch->vertical_stretch_regions, height - 2);
  const int32_t num_rows = CalculateSegmentCount(nine_patch->horizontal_stretch_regions, width - 2);
  const int32_t num_cols = CalculateSegmentCount(nine_patch->vertical_stretch_regions, height - 2);
  if ((int64_t)num_rows * (int64_t)num_cols > 0x7f) {
    *out_err = "too many regions in 9-patch";
    return {};
@@ -555,40 +542,35 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows,

  nine_patch->region_colors.reserve(num_rows * num_cols);
  CalculateRegionColors(rows, nine_patch->horizontal_stretch_regions,
                        nine_patch->vertical_stretch_regions, width - 2,
                        height - 2, &nine_patch->region_colors);
                        nine_patch->vertical_stretch_regions, width - 2, height - 2,
                        &nine_patch->region_colors);

  // Compute the outline based on opacity.

  // Find left and right extent of 9-patch content on center row.
  HorizontalImageLine mid_row(rows, 1, height / 2, width - 2);
  FindOutlineInsets(&mid_row, &nine_patch->outline.left,
                    &nine_patch->outline.right);
  FindOutlineInsets(&mid_row, &nine_patch->outline.left, &nine_patch->outline.right);

  // Find top and bottom extent of 9-patch content on center column.
  VerticalImageLine mid_col(rows, width / 2, 1, height - 2);
  FindOutlineInsets(&mid_col, &nine_patch->outline.top,
                    &nine_patch->outline.bottom);
  FindOutlineInsets(&mid_col, &nine_patch->outline.top, &nine_patch->outline.bottom);

  const int32_t outline_width =
      (width - 2) - nine_patch->outline.left - nine_patch->outline.right;
  const int32_t outline_width = (width - 2) - nine_patch->outline.left - nine_patch->outline.right;
  const int32_t outline_height =
      (height - 2) - nine_patch->outline.top - nine_patch->outline.bottom;

  // Find the largest alpha value within the outline area.
  HorizontalImageLine outline_mid_row(
      rows, 1 + nine_patch->outline.left,
      1 + nine_patch->outline.top + (outline_height / 2), outline_width);
  VerticalImageLine outline_mid_col(
      rows, 1 + nine_patch->outline.left + (outline_width / 2),
  HorizontalImageLine outline_mid_row(rows, 1 + nine_patch->outline.left,
                                      1 + nine_patch->outline.top + (outline_height / 2),
                                      outline_width);
  VerticalImageLine outline_mid_col(rows, 1 + nine_patch->outline.left + (outline_width / 2),
                                    1 + nine_patch->outline.top, outline_height);
  nine_patch->outline_alpha =
      std::max(FindMaxAlpha(&outline_mid_row), FindMaxAlpha(&outline_mid_col));

  // Assuming the image is a round rect, compute the radius by marching
  // diagonally from the top left corner towards the center.
  DiagonalImageLine diagonal(rows, 1 + nine_patch->outline.left,
                             1 + nine_patch->outline.top, 1, 1,
  DiagonalImageLine diagonal(rows, 1 + nine_patch->outline.left, 1 + nine_patch->outline.top, 1, 1,
                             std::min(outline_width, outline_height));
  int32_t top_left, bottom_right;
  FindOutlineInsets(&diagonal, &top_left, &bottom_right);
@@ -614,10 +596,9 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeBase(size_t* outLen) const {
  data.paddingBottom = padding.bottom;

  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[data.serializedSize()]);
  android::Res_png_9patch::serialize(
      data, (const int32_t*)horizontal_stretch_regions.data(),
      (const int32_t*)vertical_stretch_regions.data(), region_colors.data(),
      buffer.get());
  android::Res_png_9patch::serialize(data, (const int32_t*)horizontal_stretch_regions.data(),
                                     (const int32_t*)vertical_stretch_regions.data(),
                                     region_colors.data(), buffer.get());
  // Convert to file endianness.
  reinterpret_cast<android::Res_png_9patch*>(buffer.get())->deviceToFile();

@@ -625,8 +606,7 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeBase(size_t* outLen) const {
  return buffer;
}

std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds(
    size_t* out_len) const {
std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds(size_t* out_len) const {
  size_t chunk_len = sizeof(uint32_t) * 4;
  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]);
  uint8_t* cursor = buffer.get();
@@ -647,8 +627,7 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds(
  return buffer;
}

std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline(
    size_t* out_len) const {
std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline(size_t* out_len) const {
  size_t chunk_len = sizeof(uint32_t) * 6;
  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]);
  uint8_t* cursor = buffer.get();
@@ -679,20 +658,25 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline(
}

::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds) {
  return out << "l=" << bounds.left << " t=" << bounds.top
             << " r=" << bounds.right << " b=" << bounds.bottom;
  return out << "l=" << bounds.left << " t=" << bounds.top << " r=" << bounds.right
             << " b=" << bounds.bottom;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
  for (int i = 0; i < v.size(); ++i) {
    os << v[i];
    if (i != v.size() - 1) os << " ";
  }
  return os;
}

::std::ostream& operator<<(::std::ostream& out, const NinePatch& nine_patch) {
  return out << "horizontalStretch:"
             << util::Joiner(nine_patch.horizontal_stretch_regions, " ")
             << " verticalStretch:"
             << util::Joiner(nine_patch.vertical_stretch_regions, " ")
             << " padding: " << nine_patch.padding
             << ", bounds: " << nine_patch.layout_bounds
             << ", outline: " << nine_patch.outline
             << " rad=" << nine_patch.outline_radius
  return out << "horizontalStretch:" << nine_patch.horizontal_stretch_regions
             << " verticalStretch:" << nine_patch.vertical_stretch_regions
             << " padding: " << nine_patch.padding << ", bounds: " << nine_patch.layout_bounds
             << ", outline: " << nine_patch.outline << " rad=" << nine_patch.outline_radius
             << " alpha=" << nine_patch.outline_alpha;
}

}  // namespace aapt
}  // namespace android
+134 −194

File changed and moved.

Preview size limit exceeded, changes collapsed.

Loading