AAPT2: Refactor PngCrunching

PngCrunching now has a slightly better heuristic of choosing to encode
an image as a palette or RGB. For small images, RGB compresses much better
than a palette.

The original PNG is used as-is (minus some optional chunks being stripped)
if the resulting crunched PNG is larger than the original.

9-patch handling is abstracted away from PNGs, paving the way
for other 9-patches, like WebP.

TODO: handle PNGs with 9-patch chunks already present, which
should just be passed through. This will allow for 3rd party
tools to generate 9-patches.

TODO: implement cheap transparency: when one color is used to represent
transparent, and all other colors are opaque.

Bug:30053276
Change-Id: I5167f53b91d1efa462d9f03d6b9108d9b541c0c1
diff --git a/tools/aapt2/util/BigBuffer.cpp b/tools/aapt2/util/BigBuffer.cpp
index c88e3c1..de4ecd2 100644
--- a/tools/aapt2/util/BigBuffer.cpp
+++ b/tools/aapt2/util/BigBuffer.cpp
@@ -49,4 +49,29 @@
     return mBlocks.back().buffer.get();
 }
 
+void* BigBuffer::nextBlock(size_t* outSize) {
+    if (!mBlocks.empty()) {
+        Block& block = mBlocks.back();
+        if (block.size != block.mBlockSize) {
+            void* outBuffer = block.buffer.get() + block.size;
+            size_t size = block.mBlockSize - block.size;
+            block.size = block.mBlockSize;
+            mSize += size;
+            *outSize = size;
+            return outBuffer;
+        }
+    }
+
+    // Zero-allocate the block's buffer.
+    Block block = {};
+    block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[mBlockSize]());
+    assert(block.buffer);
+    block.size = mBlockSize;
+    block.mBlockSize = mBlockSize;
+    mBlocks.push_back(std::move(block));
+    mSize += mBlockSize;
+    *outSize = mBlockSize;
+    return mBlocks.back().buffer.get();
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h
index ba8532f..685614f 100644
--- a/tools/aapt2/util/BigBuffer.h
+++ b/tools/aapt2/util/BigBuffer.h
@@ -82,6 +82,20 @@
     T* nextBlock(size_t count = 1);
 
     /**
+     * Returns the next block available and puts the size in outCount.
+     * This is useful for grabbing blocks where the size doesn't matter.
+     * Use backUp() to give back any bytes that were not used.
+     */
+    void* nextBlock(size_t* outCount);
+
+    /**
+     * Backs up count bytes. This must only be called after nextBlock()
+     * and can not be larger than sizeof(T) * count of the last nextBlock()
+     * call.
+     */
+    void backUp(size_t count);
+
+    /**
      * Moves the specified BigBuffer into this one. When this method
      * returns, buffer is empty.
      */
@@ -97,6 +111,8 @@
      */
     void align4();
 
+    size_t getBlockSize() const;
+
     const_iterator begin() const;
     const_iterator end() const;
 
@@ -123,6 +139,10 @@
     return mSize;
 }
 
+inline size_t BigBuffer::getBlockSize() const {
+    return mBlockSize;
+}
+
 template <typename T>
 inline T* BigBuffer::nextBlock(size_t count) {
     static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
@@ -130,6 +150,12 @@
     return reinterpret_cast<T*>(nextBlockImpl(sizeof(T) * count));
 }
 
+inline void BigBuffer::backUp(size_t count) {
+    Block& block = mBlocks.back();
+    block.size -= count;
+    mSize -= count;
+}
+
 inline void BigBuffer::appendBuffer(BigBuffer&& buffer) {
     std::move(buffer.mBlocks.begin(), buffer.mBlocks.end(), std::back_inserter(mBlocks));
     mSize += buffer.mSize;
diff --git a/tools/aapt2/util/StringPiece.h b/tools/aapt2/util/StringPiece.h
index 4300a67..266c003 100644
--- a/tools/aapt2/util/StringPiece.h
+++ b/tools/aapt2/util/StringPiece.h
@@ -39,6 +39,9 @@
     using const_iterator = const TChar*;
     using difference_type = size_t;
 
+    // End of string marker.
+    constexpr static const size_t npos = static_cast<size_t>(-1);
+
     BasicStringPiece();
     BasicStringPiece(const BasicStringPiece<TChar>& str);
     BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(implicit)
@@ -48,7 +51,7 @@
     BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
     BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
 
-    BasicStringPiece<TChar> substr(size_t start, size_t len) const;
+    BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
     BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
                                    BasicStringPiece<TChar>::const_iterator end) const;
 
@@ -81,6 +84,9 @@
 //
 
 template <typename TChar>
+constexpr const size_t BasicStringPiece<TChar>::npos;
+
+template <typename TChar>
 inline BasicStringPiece<TChar>::BasicStringPiece() : mData(nullptr) , mLength(0) {
 }
 
@@ -127,7 +133,11 @@
 
 template <typename TChar>
 inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
-    if (start + len > mLength) {
+    if (len == npos) {
+        len = mLength - start;
+    }
+
+    if (start > mLength || start + len > mLength) {
         return BasicStringPiece<TChar>();
     }
     return BasicStringPiece<TChar>(mData + start, len);