fix(high contrast text): draw a solid rectangle background behind text instead of a stroke border
Bug: 186567103
Flag: com.android.graphics.hwui.flags.high_contrast_text_small_text_rect
Test: manual
1. adb shell setenforce 0 && adb shell setprop persist.device_config.aconfig_flags.accessibility.com.android.graphics.hwui.flags.high_contrast_text_small_text_rect true && adb shell stop && adb shell start
2. Settings -> Accessibility -> Display Size and Text
3. Turn on High Contrast Text
Change-Id: Ib2ef3925acc89b01c71addb63194d2a403c99cb6
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index c156c46..72ddecc 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -22,6 +22,13 @@
}
flag {
+ name: "high_contrast_text_small_text_rect"
+ namespace: "accessibility"
+ description: "Draw a solid rectangle background behind text instead of a stroke outline"
+ bug: "186567103"
+}
+
+flag {
name: "hdr_10bit_plus"
namespace: "core_graphics"
description: "Use 10101010 and FP16 formats for HDR-UI when available"
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 80b6c03..e9f4b81c 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -18,6 +18,7 @@
#include <SkFontMetrics.h>
#include <SkRRect.h>
+#include <minikin/MinikinRect.h>
#include "FeatureFlags.h"
#include "MinikinUtils.h"
@@ -107,7 +108,13 @@
// care of all alignment.
paint.setTextAlign(Paint::kLeft_Align);
- DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance());
+ minikin::MinikinRect bounds;
+ // We only need the bounds to draw a rectangular background in high contrast mode. Let's save
+ // the cycles otherwise.
+ if (flags::high_contrast_text_small_text_rect() && isHighContrastText()) {
+ MinikinUtils::getBounds(&paint, bidiFlags, typeface, text, textSize, &bounds);
+ }
+ DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance(), bounds);
MinikinUtils::forFontRun(layout, &paint, f);
if (text_feature::fix_double_underline()) {
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index 8f99990..ba65439 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -33,6 +33,8 @@
namespace android {
+inline constexpr int kHighContrastTextBorderWidth = 4;
+
static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
const Paint& paint, Canvas* canvas) {
const SkScalar strokeWidth = fmax(thickness, 1.0f);
@@ -45,15 +47,26 @@
paint->setShader(nullptr);
paint->setColorFilter(nullptr);
paint->setLooper(nullptr);
- paint->setStrokeWidth(4 + 0.04 * paint->getSkFont().getSize());
+ paint->setStrokeWidth(kHighContrastTextBorderWidth + 0.04 * paint->getSkFont().getSize());
paint->setStrokeJoin(SkPaint::kRound_Join);
paint->setLooper(nullptr);
}
class DrawTextFunctor {
public:
+ /**
+ * Creates a Functor to draw the given text layout.
+ *
+ * @param layout
+ * @param canvas
+ * @param paint
+ * @param x
+ * @param y
+ * @param totalAdvance
+ * @param bounds bounds of the text. Only required if high contrast text mode is enabled.
+ */
DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, const Paint& paint, float x,
- float y, float totalAdvance)
+ float y, float totalAdvance, const minikin::MinikinRect& bounds)
: layout(layout)
, canvas(canvas)
, paint(paint)
@@ -61,7 +74,8 @@
, y(y)
, totalAdvance(totalAdvance)
, underlinePosition(0)
- , underlineThickness(0) {}
+ , underlineThickness(0)
+ , bounds(bounds) {}
void operator()(size_t start, size_t end) {
auto glyphFunc = [&](uint16_t* text, float* positions) {
@@ -91,7 +105,16 @@
Paint outlinePaint(paint);
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
- canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance);
+ if (flags::high_contrast_text_small_text_rect()) {
+ auto bgBounds(bounds);
+ auto padding = kHighContrastTextBorderWidth + 0.1f * paint.getSkFont().getSize();
+ bgBounds.offset(x, y);
+ canvas->drawRect(bgBounds.mLeft - padding, bgBounds.mTop - padding,
+ bgBounds.mRight + padding, bgBounds.mBottom + padding,
+ outlinePaint);
+ } else {
+ canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance);
+ }
// inner
gDrawTextBlobMode = DrawTextBlobMode::HctInner;
@@ -146,6 +169,7 @@
float totalAdvance;
float underlinePosition;
float underlineThickness;
+ const minikin::MinikinRect& bounds;
};
} // namespace android
diff --git a/libs/hwui/tests/unit/UnderlineTest.cpp b/libs/hwui/tests/unit/UnderlineTest.cpp
index c70a304..9911bfa 100644
--- a/libs/hwui/tests/unit/UnderlineTest.cpp
+++ b/libs/hwui/tests/unit/UnderlineTest.cpp
@@ -103,8 +103,9 @@
// Create minikin::Layout
std::unique_ptr<Typeface> typeface(makeTypeface());
minikin::Layout layout = doLayout(text, *paint, typeface.get());
+ minikin::MinikinRect bounds;
- DrawTextFunctor f(layout, &canvas, *paint, 0, 0, layout.getAdvance());
+ DrawTextFunctor f(layout, &canvas, *paint, 0, 0, layout.getAdvance(), bounds);
MinikinUtils::forFontRun(layout, paint, f);
return f;
}