xref: /aosp_15_r20/frameworks/minikin/tests/unittest/LineBreakerTestHelper.h (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1*834a2baaSAndroid Build Coastguard Worker /*
2*834a2baaSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*834a2baaSAndroid Build Coastguard Worker  *
4*834a2baaSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*834a2baaSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*834a2baaSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*834a2baaSAndroid Build Coastguard Worker  *
8*834a2baaSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*834a2baaSAndroid Build Coastguard Worker  *
10*834a2baaSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*834a2baaSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*834a2baaSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*834a2baaSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*834a2baaSAndroid Build Coastguard Worker  * limitations under the License.
15*834a2baaSAndroid Build Coastguard Worker  */
16*834a2baaSAndroid Build Coastguard Worker 
17*834a2baaSAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*834a2baaSAndroid Build Coastguard Worker 
19*834a2baaSAndroid Build Coastguard Worker #include "minikin/Hyphenator.h"
20*834a2baaSAndroid Build Coastguard Worker #include "minikin/LineBreaker.h"
21*834a2baaSAndroid Build Coastguard Worker 
22*834a2baaSAndroid Build Coastguard Worker #include "LocaleListCache.h"
23*834a2baaSAndroid Build Coastguard Worker #include "MinikinInternal.h"
24*834a2baaSAndroid Build Coastguard Worker #include "UnicodeUtils.h"
25*834a2baaSAndroid Build Coastguard Worker 
26*834a2baaSAndroid Build Coastguard Worker namespace minikin {
27*834a2baaSAndroid Build Coastguard Worker namespace line_breaker_test_helper {
28*834a2baaSAndroid Build Coastguard Worker 
29*834a2baaSAndroid Build Coastguard Worker class RectangleLineWidth : public LineWidth {
30*834a2baaSAndroid Build Coastguard Worker public:
RectangleLineWidth(float width)31*834a2baaSAndroid Build Coastguard Worker     RectangleLineWidth(float width) : mWidth(width) {}
~RectangleLineWidth()32*834a2baaSAndroid Build Coastguard Worker     virtual ~RectangleLineWidth() {}
33*834a2baaSAndroid Build Coastguard Worker 
getAt(size_t)34*834a2baaSAndroid Build Coastguard Worker     float getAt(size_t) const override { return mWidth; }
getMin()35*834a2baaSAndroid Build Coastguard Worker     float getMin() const override { return mWidth; }
36*834a2baaSAndroid Build Coastguard Worker 
37*834a2baaSAndroid Build Coastguard Worker private:
38*834a2baaSAndroid Build Coastguard Worker     float mWidth;
39*834a2baaSAndroid Build Coastguard Worker };
40*834a2baaSAndroid Build Coastguard Worker 
41*834a2baaSAndroid Build Coastguard Worker // The run implemenataion for returning the same width for all characters.
42*834a2baaSAndroid Build Coastguard Worker class ConstantRun : public Run {
43*834a2baaSAndroid Build Coastguard Worker public:
ConstantRun(const Range & range,const std::string & lang,float width,float ascent,float descent)44*834a2baaSAndroid Build Coastguard Worker     ConstantRun(const Range& range, const std::string& lang, float width, float ascent,
45*834a2baaSAndroid Build Coastguard Worker                 float descent)
46*834a2baaSAndroid Build Coastguard Worker             : Run(range),
47*834a2baaSAndroid Build Coastguard Worker               mPaint(nullptr /* font collection */),
48*834a2baaSAndroid Build Coastguard Worker               mWidth(width),
49*834a2baaSAndroid Build Coastguard Worker               mAscent(ascent),
50*834a2baaSAndroid Build Coastguard Worker               mDescent(descent) {
51*834a2baaSAndroid Build Coastguard Worker         mLocaleListId = LocaleListCache::getId(lang);
52*834a2baaSAndroid Build Coastguard Worker     }
53*834a2baaSAndroid Build Coastguard Worker 
isRtl()54*834a2baaSAndroid Build Coastguard Worker     virtual bool isRtl() const override { return false; }
canBreak()55*834a2baaSAndroid Build Coastguard Worker     virtual bool canBreak() const override { return true; }
canHyphenate()56*834a2baaSAndroid Build Coastguard Worker     virtual bool canHyphenate() const override { return true; }
getLocaleListId()57*834a2baaSAndroid Build Coastguard Worker     virtual uint32_t getLocaleListId() const { return mLocaleListId; }
58*834a2baaSAndroid Build Coastguard Worker 
getMetrics(const U16StringPiece &,std::vector<float> * advances,std::vector<uint8_t> *,LayoutPieces *,bool,LayoutPieces *)59*834a2baaSAndroid Build Coastguard Worker     virtual void getMetrics(const U16StringPiece&, std::vector<float>* advances,
60*834a2baaSAndroid Build Coastguard Worker                             std::vector<uint8_t>* /*flags*/, LayoutPieces*,
61*834a2baaSAndroid Build Coastguard Worker                             bool /*boundsCalculation*/, LayoutPieces*) const {
62*834a2baaSAndroid Build Coastguard Worker         std::fill(advances->begin() + mRange.getStart(), advances->begin() + mRange.getEnd(),
63*834a2baaSAndroid Build Coastguard Worker                   mWidth);
64*834a2baaSAndroid Build Coastguard Worker     }
65*834a2baaSAndroid Build Coastguard Worker 
getBounds(const U16StringPiece &,const Range &,const LayoutPieces &)66*834a2baaSAndroid Build Coastguard Worker     virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */,
67*834a2baaSAndroid Build Coastguard Worker                                                     const Range& /* range */,
68*834a2baaSAndroid Build Coastguard Worker                                                     const LayoutPieces& /* pieces */) const {
69*834a2baaSAndroid Build Coastguard Worker         return std::make_pair(mWidth, MinikinRect());
70*834a2baaSAndroid Build Coastguard Worker     }
71*834a2baaSAndroid Build Coastguard Worker 
getExtent(const U16StringPiece &,const Range &,const LayoutPieces &)72*834a2baaSAndroid Build Coastguard Worker     virtual MinikinExtent getExtent(const U16StringPiece& /* text */, const Range& /* range */,
73*834a2baaSAndroid Build Coastguard Worker                                     const LayoutPieces& /* pieces */) const override {
74*834a2baaSAndroid Build Coastguard Worker         return {mAscent, mDescent};
75*834a2baaSAndroid Build Coastguard Worker     }
76*834a2baaSAndroid Build Coastguard Worker 
getLineMetrics(const U16StringPiece & text,const Range & range,const LayoutPieces & pieces)77*834a2baaSAndroid Build Coastguard Worker     virtual LineMetrics getLineMetrics(const U16StringPiece& text, const Range& range,
78*834a2baaSAndroid Build Coastguard Worker                                        const LayoutPieces& pieces) const {
79*834a2baaSAndroid Build Coastguard Worker         auto [adv, rect] = getBounds(text, range, pieces);
80*834a2baaSAndroid Build Coastguard Worker         return LineMetrics(getExtent(text, range, pieces), rect, adv);
81*834a2baaSAndroid Build Coastguard Worker     }
82*834a2baaSAndroid Build Coastguard Worker 
getPaint()83*834a2baaSAndroid Build Coastguard Worker     virtual const MinikinPaint* getPaint() const { return &mPaint; }
84*834a2baaSAndroid Build Coastguard Worker 
measureHyphenPiece(const U16StringPiece &,const Range & range,StartHyphenEdit start,EndHyphenEdit end,LayoutPieces *)85*834a2baaSAndroid Build Coastguard Worker     virtual float measureHyphenPiece(const U16StringPiece&, const Range& range,
86*834a2baaSAndroid Build Coastguard Worker                                      StartHyphenEdit start, EndHyphenEdit end,
87*834a2baaSAndroid Build Coastguard Worker                                      LayoutPieces*) const {
88*834a2baaSAndroid Build Coastguard Worker         uint32_t extraCharForHyphen = 0;
89*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(start)) {
90*834a2baaSAndroid Build Coastguard Worker             extraCharForHyphen++;
91*834a2baaSAndroid Build Coastguard Worker         }
92*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(end)) {
93*834a2baaSAndroid Build Coastguard Worker             extraCharForHyphen++;
94*834a2baaSAndroid Build Coastguard Worker         }
95*834a2baaSAndroid Build Coastguard Worker         return mWidth * (range.getLength() + extraCharForHyphen);
96*834a2baaSAndroid Build Coastguard Worker     }
97*834a2baaSAndroid Build Coastguard Worker 
appendLayout(const U16StringPiece &,const Range &,const Range &,const LayoutPieces &,const MinikinPaint &,uint32_t,StartHyphenEdit,EndHyphenEdit,Layout *)98*834a2baaSAndroid Build Coastguard Worker     virtual void appendLayout(const U16StringPiece&, const Range&, const Range&,
99*834a2baaSAndroid Build Coastguard Worker                               const LayoutPieces&, const MinikinPaint&, uint32_t, StartHyphenEdit,
100*834a2baaSAndroid Build Coastguard Worker                               EndHyphenEdit, Layout*) const {}
101*834a2baaSAndroid Build Coastguard Worker 
measureText(const U16StringPiece &)102*834a2baaSAndroid Build Coastguard Worker     virtual float measureText(const U16StringPiece&) const { return 0; }
103*834a2baaSAndroid Build Coastguard Worker 
lineBreakStyle()104*834a2baaSAndroid Build Coastguard Worker     virtual LineBreakStyle lineBreakStyle() const override { return LineBreakStyle::None; }
105*834a2baaSAndroid Build Coastguard Worker 
lineBreakWordStyle()106*834a2baaSAndroid Build Coastguard Worker     virtual LineBreakWordStyle lineBreakWordStyle() const override {
107*834a2baaSAndroid Build Coastguard Worker         return LineBreakWordStyle::None;
108*834a2baaSAndroid Build Coastguard Worker     }
109*834a2baaSAndroid Build Coastguard Worker 
110*834a2baaSAndroid Build Coastguard Worker private:
111*834a2baaSAndroid Build Coastguard Worker     MinikinPaint mPaint;
112*834a2baaSAndroid Build Coastguard Worker     uint32_t mLocaleListId;
113*834a2baaSAndroid Build Coastguard Worker     float mWidth;
114*834a2baaSAndroid Build Coastguard Worker     float mAscent;
115*834a2baaSAndroid Build Coastguard Worker     float mDescent;
116*834a2baaSAndroid Build Coastguard Worker };
117*834a2baaSAndroid Build Coastguard Worker 
118*834a2baaSAndroid Build Coastguard Worker struct LineBreakExpectation {
119*834a2baaSAndroid Build Coastguard Worker     std::string mLineContent;
120*834a2baaSAndroid Build Coastguard Worker     float mWidth;
121*834a2baaSAndroid Build Coastguard Worker     StartHyphenEdit mStartEdit;
122*834a2baaSAndroid Build Coastguard Worker     EndHyphenEdit mEndEdit;
123*834a2baaSAndroid Build Coastguard Worker     float mAscent;
124*834a2baaSAndroid Build Coastguard Worker     float mDescent;
125*834a2baaSAndroid Build Coastguard Worker };
126*834a2baaSAndroid Build Coastguard Worker 
sameLineBreak(const std::vector<LineBreakExpectation> & expected,const LineBreakResult & actual)127*834a2baaSAndroid Build Coastguard Worker static bool sameLineBreak(const std::vector<LineBreakExpectation>& expected,
128*834a2baaSAndroid Build Coastguard Worker                           const LineBreakResult& actual) {
129*834a2baaSAndroid Build Coastguard Worker     if (expected.size() != actual.breakPoints.size()) {
130*834a2baaSAndroid Build Coastguard Worker         return false;
131*834a2baaSAndroid Build Coastguard Worker     }
132*834a2baaSAndroid Build Coastguard Worker 
133*834a2baaSAndroid Build Coastguard Worker     uint32_t breakOffset = 0;
134*834a2baaSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < expected.size(); ++i) {
135*834a2baaSAndroid Build Coastguard Worker         std::vector<uint16_t> u16Str = utf8ToUtf16(expected[i].mLineContent);
136*834a2baaSAndroid Build Coastguard Worker 
137*834a2baaSAndroid Build Coastguard Worker         // The expected string contains auto inserted hyphen. Remove it for computing offset.
138*834a2baaSAndroid Build Coastguard Worker         uint32_t lineLength = u16Str.size();
139*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(expected[i].mStartEdit)) {
140*834a2baaSAndroid Build Coastguard Worker             if (u16Str[0] != '-') {
141*834a2baaSAndroid Build Coastguard Worker                 return false;
142*834a2baaSAndroid Build Coastguard Worker             }
143*834a2baaSAndroid Build Coastguard Worker             --lineLength;
144*834a2baaSAndroid Build Coastguard Worker         }
145*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(expected[i].mEndEdit)) {
146*834a2baaSAndroid Build Coastguard Worker             if (u16Str.back() != '-') {
147*834a2baaSAndroid Build Coastguard Worker                 return false;
148*834a2baaSAndroid Build Coastguard Worker             }
149*834a2baaSAndroid Build Coastguard Worker             --lineLength;
150*834a2baaSAndroid Build Coastguard Worker         }
151*834a2baaSAndroid Build Coastguard Worker         breakOffset += lineLength;
152*834a2baaSAndroid Build Coastguard Worker 
153*834a2baaSAndroid Build Coastguard Worker         if (breakOffset != static_cast<uint32_t>(actual.breakPoints[i])) {
154*834a2baaSAndroid Build Coastguard Worker             return false;
155*834a2baaSAndroid Build Coastguard Worker         }
156*834a2baaSAndroid Build Coastguard Worker         if (expected[i].mWidth != actual.widths[i]) {
157*834a2baaSAndroid Build Coastguard Worker             return false;
158*834a2baaSAndroid Build Coastguard Worker         }
159*834a2baaSAndroid Build Coastguard Worker         HyphenEdit edit = static_cast<HyphenEdit>(actual.flags[i] & 0xFF);
160*834a2baaSAndroid Build Coastguard Worker         if (expected[i].mStartEdit != startHyphenEdit(edit)) {
161*834a2baaSAndroid Build Coastguard Worker             return false;
162*834a2baaSAndroid Build Coastguard Worker         }
163*834a2baaSAndroid Build Coastguard Worker         if (expected[i].mEndEdit != endHyphenEdit(edit)) {
164*834a2baaSAndroid Build Coastguard Worker             return false;
165*834a2baaSAndroid Build Coastguard Worker         }
166*834a2baaSAndroid Build Coastguard Worker         if (expected[i].mAscent != actual.ascents[i]) {
167*834a2baaSAndroid Build Coastguard Worker             return false;
168*834a2baaSAndroid Build Coastguard Worker         }
169*834a2baaSAndroid Build Coastguard Worker         if (expected[i].mDescent != actual.descents[i]) {
170*834a2baaSAndroid Build Coastguard Worker             return false;
171*834a2baaSAndroid Build Coastguard Worker         }
172*834a2baaSAndroid Build Coastguard Worker     }
173*834a2baaSAndroid Build Coastguard Worker     return true;
174*834a2baaSAndroid Build Coastguard Worker }
175*834a2baaSAndroid Build Coastguard Worker 
176*834a2baaSAndroid Build Coastguard Worker // Make debug string.
toString(const std::vector<LineBreakExpectation> & lines)177*834a2baaSAndroid Build Coastguard Worker static std::string toString(const std::vector<LineBreakExpectation>& lines) {
178*834a2baaSAndroid Build Coastguard Worker     std::string out;
179*834a2baaSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < lines.size(); ++i) {
180*834a2baaSAndroid Build Coastguard Worker         const LineBreakExpectation& line = lines[i];
181*834a2baaSAndroid Build Coastguard Worker 
182*834a2baaSAndroid Build Coastguard Worker         char lineMsg[128] = {};
183*834a2baaSAndroid Build Coastguard Worker         snprintf(lineMsg, sizeof(lineMsg),
184*834a2baaSAndroid Build Coastguard Worker                  "Line %2d, Width: %5.1f, Hyphen(%hhu, %hhu), Extent(%5.1f, %5.1f), Text: \"%s\"\n",
185*834a2baaSAndroid Build Coastguard Worker                  i, line.mWidth, line.mStartEdit, line.mEndEdit, line.mAscent, line.mDescent,
186*834a2baaSAndroid Build Coastguard Worker                  line.mLineContent.c_str());
187*834a2baaSAndroid Build Coastguard Worker         out += lineMsg;
188*834a2baaSAndroid Build Coastguard Worker     }
189*834a2baaSAndroid Build Coastguard Worker     return out;
190*834a2baaSAndroid Build Coastguard Worker }
191*834a2baaSAndroid Build Coastguard Worker 
192*834a2baaSAndroid Build Coastguard Worker // Make debug string.
toString(const U16StringPiece & textBuf,const LineBreakResult & lines)193*834a2baaSAndroid Build Coastguard Worker static std::string toString(const U16StringPiece& textBuf, const LineBreakResult& lines) {
194*834a2baaSAndroid Build Coastguard Worker     std::string out;
195*834a2baaSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < lines.breakPoints.size(); ++i) {
196*834a2baaSAndroid Build Coastguard Worker         const Range textRange(i == 0 ? 0 : lines.breakPoints[i - 1], lines.breakPoints[i]);
197*834a2baaSAndroid Build Coastguard Worker         const HyphenEdit edit = static_cast<HyphenEdit>(lines.flags[i] & 0xFF);
198*834a2baaSAndroid Build Coastguard Worker 
199*834a2baaSAndroid Build Coastguard Worker         const StartHyphenEdit startEdit = startHyphenEdit(edit);
200*834a2baaSAndroid Build Coastguard Worker         const EndHyphenEdit endEdit = endHyphenEdit(edit);
201*834a2baaSAndroid Build Coastguard Worker         std::string hyphenatedStr = utf16ToUtf8(textBuf.substr(textRange));
202*834a2baaSAndroid Build Coastguard Worker 
203*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(startEdit)) {
204*834a2baaSAndroid Build Coastguard Worker             hyphenatedStr.insert(0, "-");
205*834a2baaSAndroid Build Coastguard Worker         }
206*834a2baaSAndroid Build Coastguard Worker         if (isInsertion(endEdit)) {
207*834a2baaSAndroid Build Coastguard Worker             hyphenatedStr.push_back('-');
208*834a2baaSAndroid Build Coastguard Worker         }
209*834a2baaSAndroid Build Coastguard Worker         char lineMsg[256] = {};
210*834a2baaSAndroid Build Coastguard Worker         snprintf(lineMsg, sizeof(lineMsg),
211*834a2baaSAndroid Build Coastguard Worker                  "Line %2d, Width: %5.1f, Hyphen(%hhu, %hhu), Extent(%5.1f, %5.1f), Bounds(%f, %f, "
212*834a2baaSAndroid Build Coastguard Worker                  "%f, %f), Text: \"%s\"\n",
213*834a2baaSAndroid Build Coastguard Worker                  i, lines.widths[i], startEdit, endEdit, lines.ascents[i], lines.descents[i],
214*834a2baaSAndroid Build Coastguard Worker                  lines.bounds[i].mLeft, lines.bounds[i].mTop, lines.bounds[i].mRight,
215*834a2baaSAndroid Build Coastguard Worker                  lines.bounds[i].mBottom, hyphenatedStr.c_str());
216*834a2baaSAndroid Build Coastguard Worker         out += lineMsg;
217*834a2baaSAndroid Build Coastguard Worker     }
218*834a2baaSAndroid Build Coastguard Worker     return out;
219*834a2baaSAndroid Build Coastguard Worker }
220*834a2baaSAndroid Build Coastguard Worker 
221*834a2baaSAndroid Build Coastguard Worker }  // namespace line_breaker_test_helper
222*834a2baaSAndroid Build Coastguard Worker }  // namespace minikin
223