Add bounding box based text layout APIs.

This CL adds bounding box based text layout features.
By setting setUseBoundsForWidth, the line break width and drawing
offset is adjusted based on bounding box instead of advances.

Bug: 63938206
Test: atest CtsTextTestCases

Change-Id: I993c455eee1b4100656db9aef38675e3cda3309d
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index e359145..bcfb4c8 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -84,7 +84,8 @@
 
 float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
                                 const Typeface* typeface, const uint16_t* buf, size_t start,
-                                size_t count, size_t bufSize, float* advances) {
+                                size_t count, size_t bufSize, float* advances,
+                                minikin::MinikinRect* bounds) {
     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
     const minikin::U16StringPiece textBuf(buf, bufSize);
     const minikin::Range range(start, start + count);
@@ -92,7 +93,7 @@
     const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit();
 
     return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
-                                        endHyphen, advances);
+                                        endHyphen, advances, bounds);
 }
 
 minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 51960b0..61bc881 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -51,10 +51,9 @@
     static void getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
                           const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out);
 
-    static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
-                                         const Typeface* typeface, const uint16_t* buf,
-                                         size_t start, size_t count, size_t bufSize,
-                                         float* advances);
+    static float measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface,
+                             const uint16_t* buf, size_t start, size_t count, size_t bufSize,
+                             float* advances, minikin::MinikinRect* bounds);
 
     static minikin::MinikinExtent getFontExtent(const Paint* paint, minikin::Bidi bidiFlags,
                                                 const Typeface* typeface, const uint16_t* buf,
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 1ba7f70..a17f2f7 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -53,6 +53,17 @@
 
 namespace android {
 
+namespace {
+
+void copyMinikinRectToSkRect(const minikin::MinikinRect& minikinRect, SkRect* skRect) {
+    skRect->fLeft = minikinRect.mLeft;
+    skRect->fTop = minikinRect.mTop;
+    skRect->fRight = minikinRect.mRight;
+    skRect->fBottom = minikinRect.mBottom;
+}
+
+}  // namespace
+
 static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count,
                            const SkPoint pos[], SkPath* dst) {
     dst->reset();
@@ -101,8 +112,8 @@
         float measured = 0;
 
         std::unique_ptr<float[]> advancesArray(new float[count]);
-        MinikinUtils::measureText(&paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text,
-                0, count, count, advancesArray.get());
+        MinikinUtils::measureText(&paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0,
+                                  count, count, advancesArray.get(), nullptr);
 
         for (int i = 0; i < count; i++) {
             // traverse in the given direction
@@ -192,9 +203,10 @@
         if (advances) {
             advancesArray.reset(new jfloat[count]);
         }
-        const float advance = MinikinUtils::measureText(paint,
-                static_cast<minikin::Bidi>(bidiFlags), typeface, text, start, count, contextCount,
-                advancesArray.get());
+        minikin::MinikinRect bounds;
+        const float advance = MinikinUtils::measureText(
+                paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, start, count,
+                contextCount, advancesArray.get(), &bounds);
         if (advances) {
             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
         }
@@ -232,7 +244,7 @@
         minikin::Bidi bidiFlags = dir == 1 ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
         std::unique_ptr<float[]> advancesArray(new float[count]);
         MinikinUtils::measureText(paint, bidiFlags, typeface, text, start, count, start + count,
-                advancesArray.get());
+                                  advancesArray.get(), nullptr);
         size_t result = minikin::GraphemeBreak::getTextRunCursor(advancesArray.get(), text,
                 start, count, offset, moveOpt);
         return static_cast<jint>(result);
@@ -496,7 +508,7 @@
     static jfloat doRunAdvance(JNIEnv* env, const Paint* paint, const Typeface* typeface,
                                const jchar buf[], jint start, jint count, jint bufSize,
                                jboolean isRtl, jint offset, jfloatArray advances,
-                               jint advancesIndex) {
+                               jint advancesIndex, SkRect* drawBounds) {
         if (advances) {
             size_t advancesLength = env->GetArrayLength(advances);
             if ((size_t)(count + advancesIndex) > advancesLength) {
@@ -505,14 +517,23 @@
             }
         }
         minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
+        minikin::MinikinRect bounds;
         if (offset == start + count && advances == nullptr) {
-            return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
-                    bufSize, nullptr);
+            float result =
+                    MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
+                                              bufSize, nullptr, drawBounds ? &bounds : nullptr);
+            if (drawBounds) {
+                copyMinikinRectToSkRect(bounds, drawBounds);
+            }
+            return result;
         }
         std::unique_ptr<float[]> advancesArray(new float[count]);
         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
-                advancesArray.get());
+                                  advancesArray.get(), drawBounds ? &bounds : nullptr);
 
+        if (drawBounds) {
+            copyMinikinRectToSkRect(bounds, drawBounds);
+        }
         float result = minikin::getRunAdvance(advancesArray.get(), buf, start, count, offset);
         if (advances) {
             minikin::distributeAdvances(advancesArray.get(), buf, start, count);
@@ -528,7 +549,7 @@
         ScopedCharArrayRO textArray(env, text);
         jfloat result = doRunAdvance(env, paint, typeface, textArray.get() + contextStart,
                                      start - contextStart, end - start, contextEnd - contextStart,
-                                     isRtl, offset - contextStart, nullptr, 0);
+                                     isRtl, offset - contextStart, nullptr, 0, nullptr);
         return result;
     }
 
@@ -536,13 +557,19 @@
                                                         jcharArray text, jint start, jint end,
                                                         jint contextStart, jint contextEnd,
                                                         jboolean isRtl, jint offset,
-                                                        jfloatArray advances, jint advancesIndex) {
+                                                        jfloatArray advances, jint advancesIndex,
+                                                        jobject drawBounds) {
         const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         const Typeface* typeface = paint->getAndroidTypeface();
         ScopedCharArrayRO textArray(env, text);
+        SkRect skDrawBounds;
         jfloat result = doRunAdvance(env, paint, typeface, textArray.get() + contextStart,
                                      start - contextStart, end - start, contextEnd - contextStart,
-                                     isRtl, offset - contextStart, advances, advancesIndex);
+                                     isRtl, offset - contextStart, advances, advancesIndex,
+                                     drawBounds ? &skDrawBounds : nullptr);
+        if (drawBounds != nullptr) {
+            GraphicsJNI::rect_to_jrectf(skDrawBounds, env, drawBounds);
+        }
         return result;
     }
 
@@ -551,7 +578,7 @@
         minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
         std::unique_ptr<float[]> advancesArray(new float[count]);
         MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
-                advancesArray.get());
+                                  advancesArray.get(), nullptr);
         return minikin::getOffsetForAdvance(advancesArray.get(), buf, start, count, advance);
     }
 
@@ -1081,7 +1108,7 @@
          (void*)PaintGlue::getCharArrayBounds},
         {"nHasGlyph", "(JILjava/lang/String;)Z", (void*)PaintGlue::hasGlyph},
         {"nGetRunAdvance", "(J[CIIIIZI)F", (void*)PaintGlue::getRunAdvance___CIIIIZI_F},
-        {"nGetRunCharacterAdvance", "(J[CIIIIZI[FI)F",
+        {"nGetRunCharacterAdvance", "(J[CIIIIZI[FILandroid/graphics/RectF;)F",
          (void*)PaintGlue::getRunCharacterAdvance___CIIIIZI_FI_F},
         {"nGetOffsetForAdvance", "(J[CIIIIZF)I", (void*)PaintGlue::getOffsetForAdvance___CIIIIZF_I},
         {"nGetFontMetricsIntForText", "(J[CIIIIZLandroid/graphics/Paint$FontMetricsInt;)V",
diff --git a/libs/hwui/jni/text/LineBreaker.cpp b/libs/hwui/jni/text/LineBreaker.cpp
index 9ebf23c..c512256 100644
--- a/libs/hwui/jni/text/LineBreaker.cpp
+++ b/libs/hwui/jni/text/LineBreaker.cpp
@@ -51,13 +51,12 @@
 
 // set text and set a number of parameters for creating a layout (width, tabstops, strategy,
 // hyphenFrequency)
-static jlong nInit(JNIEnv* env, jclass /* unused */,
-        jint breakStrategy, jint hyphenationFrequency, jboolean isJustified, jintArray indents) {
+static jlong nInit(JNIEnv* env, jclass /* unused */, jint breakStrategy, jint hyphenationFrequency,
+                   jboolean isJustified, jintArray indents, jboolean useBoundsForWidth) {
     return reinterpret_cast<jlong>(new minikin::android::StaticLayoutNative(
             static_cast<minikin::BreakStrategy>(breakStrategy),
-            static_cast<minikin::HyphenationFrequency>(hyphenationFrequency),
-            isJustified,
-            jintArrayToFloatVector(env, indents)));
+            static_cast<minikin::HyphenationFrequency>(hyphenationFrequency), isJustified,
+            jintArrayToFloatVector(env, indents), useBoundsForWidth));
 }
 
 static void nFinish(jlong nativePtr) {
@@ -128,39 +127,44 @@
 }
 
 static const JNINativeMethod gMethods[] = {
-    // Fast Natives
-    {"nInit", "("
-        "I"  // breakStrategy
-        "I"  // hyphenationFrequency
-        "Z"  // isJustified
-        "[I"  // indents
-        ")J", (void*) nInit},
+        // Fast Natives
+        {"nInit",
+         "("
+         "I"   // breakStrategy
+         "I"   // hyphenationFrequency
+         "Z"   // isJustified
+         "[I"  // indents
+         "Z"   // useBoundsForWidth
+         ")J",
+         (void*)nInit},
 
-    // Critical Natives
-    {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc},
+        // Critical Natives
+        {"nGetReleaseFunc", "()J", (void*)nGetReleaseFunc},
 
-    // Regular JNI
-    {"nComputeLineBreaks", "("
-        "J"  // nativePtr
-        "[C"  // text
-        "J"  // MeasuredParagraph ptr.
-        "I"  // length
-        "F"  // firstWidth
-        "I"  // firstWidthLineCount
-        "F"  // restWidth
-        "[F"  // variableTabStops
-        "F"  // defaultTabStop
-        "I"  // indentsOffset
-        ")J", (void*) nComputeLineBreaks},
+        // Regular JNI
+        {"nComputeLineBreaks",
+         "("
+         "J"   // nativePtr
+         "[C"  // text
+         "J"   // MeasuredParagraph ptr.
+         "I"   // length
+         "F"   // firstWidth
+         "I"   // firstWidthLineCount
+         "F"   // restWidth
+         "[F"  // variableTabStops
+         "F"   // defaultTabStop
+         "I"   // indentsOffset
+         ")J",
+         (void*)nComputeLineBreaks},
 
-    // Result accessors, CriticalNatives
-    {"nGetLineCount", "(J)I", (void*)nGetLineCount},
-    {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset},
-    {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth},
-    {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent},
-    {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent},
-    {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag},
-    {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},
+        // Result accessors, CriticalNatives
+        {"nGetLineCount", "(J)I", (void*)nGetLineCount},
+        {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset},
+        {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth},
+        {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent},
+        {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent},
+        {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag},
+        {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},
 };
 
 int register_android_graphics_text_LineBreaker(JNIEnv* env) {
diff --git a/libs/hwui/jni/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index 081713a..f6ae169 100644
--- a/libs/hwui/jni/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -81,13 +81,14 @@
 // Regular JNI
 static jlong nBuildMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr, jlong hintPtr,
                                 jcharArray javaText, jboolean computeHyphenation,
-                                jboolean computeLayout, jboolean fastHyphenationMode) {
+                                jboolean computeLayout, jboolean computeBounds,
+                                jboolean fastHyphenationMode) {
     ScopedCharArrayRO text(env, javaText);
     const minikin::U16StringPiece textBuffer(text.get(), text.size());
 
     // Pass the ownership to Java.
     return toJLong(toBuilder(builderPtr)
-                           ->build(textBuffer, computeHyphenation, computeLayout,
+                           ->build(textBuffer, computeHyphenation, computeLayout, computeBounds,
                                    fastHyphenationMode, toMeasuredParagraph(hintPtr))
                            .release());
 }
@@ -160,7 +161,7 @@
         {"nInitBuilder", "()J", (void*)nInitBuilder},
         {"nAddStyleRun", "(JJIIIIZ)V", (void*)nAddStyleRun},
         {"nAddReplacementRun", "(JJIIF)V", (void*)nAddReplacementRun},
-        {"nBuildMeasuredText", "(JJ[CZZZ)J", (void*)nBuildMeasuredText},
+        {"nBuildMeasuredText", "(JJ[CZZZZ)J", (void*)nBuildMeasuredText},
         {"nFreeBuilder", "(J)V", (void*)nFreeBuilder},
 };