diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 831473cf97a4c..2ec7b75cb91d1 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -194,8 +194,12 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, renderer.renderGlop(nullptr, clip, glop); } -static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, +static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& textOpState) { + if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return; + + FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); + fontRenderer.setFont(op.paint, SkMatrix::I()); renderer.caches().textureState().activateTexture(0); PaintUtils::TextShadow textShadow; @@ -258,15 +262,9 @@ enum class TextRenderType { Flush }; -static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, +static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, const ClipBase* renderClip, TextRenderType renderType) { FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); - - if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { - fontRenderer.setFont(op.paint, SkMatrix::I()); - renderTextShadow(renderer, fontRenderer, op, state); - } - float x = op.x; float y = op.y; const Matrix4& transform = state.computedState.transform; @@ -321,6 +319,12 @@ static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const Bake void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const MergedBakedOpList& opList) { + for (size_t i = 0; i < opList.count; i++) { + const BakedOpState& state = *(opList.states[i]); + const TextOp& op = *(static_cast(state.op)); + renderTextShadow(renderer, op, state); + } + ClipRect renderTargetClip(opList.clip); const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; for (size_t i = 0; i < opList.count; i++) { @@ -328,7 +332,7 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, const TextOp& op = *(static_cast(state.op)); TextRenderType renderType = (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer; - renderTextOp(renderer, op, state, clip, renderType); + renderText(renderer, op, state, clip, renderType); } } @@ -740,7 +744,8 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR } void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { - renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); + renderTextShadow(renderer, op, state); + renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); } void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) { diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp index de57cd1e9650e..5613f9fd729c4 100644 --- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include @@ -26,6 +29,7 @@ using namespace android::uirenderer; static BakedOpRenderer::LightInfo sLightInfo; +const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50}; static Rect sBaseClip(100, 100); class ValidatingBakedOpRenderer : public BakedOpRenderer { @@ -45,7 +49,7 @@ private: std::function mValidator; }; -typedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); +typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op, std::function glopVerifier) { @@ -67,7 +71,7 @@ static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, R [](BakedOpRenderer& renderer, const BakedOpState& state) { \ BakedOpDispatcher::on##Type(renderer, static_cast(*(state.op)), state); \ }, - static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); + static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); #undef X unmergedReceivers[op->opId](renderer, *state); ASSERT_EQ(1, glopCount) << "Exactly one Glop expected"; @@ -154,4 +158,40 @@ RENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) { LinesOp linesOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4); EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &linesOp)) << "Expect an offset for non-AA lines."; +} + +RENDERTHREAD_TEST(BakedOpDispatcher, renderTextWithShadow) { + auto node = TestUtils::createNode(0, 0, 100, 100, + [](RenderProperties& props, TestCanvas& canvas) { + + android::Paint shadowPaint; + shadowPaint.setColor(SK_ColorRED); + + SkScalar sigma = Blur::convertRadiusToSigma(5); + shadowPaint.setLooper(SkBlurDrawLooper::Create(SK_ColorWHITE, sigma, 3, 3))->unref(); + + TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25); + TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50); + }); + + int glopCount = 0; + auto glopReceiver = [&glopCount] (const Glop& glop) { + if (glopCount < 2) { + // two white shadows + EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color); + } else { + // two text draws merged into one, drawn after both shadows + EXPECT_EQ(FloatColor({1, 0, 0, 1}), glop.fill.color); + } + glopCount++; + }; + + ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver); + + FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, + sLightGeometry, Caches::getInstance()); + frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); + + frameBuilder.replayBakedOps(renderer); + ASSERT_EQ(3, glopCount) << "Exactly three glops expected"; } \ No newline at end of file