xref: /aosp_15_r20/frameworks/minikin/libs/minikin/LayoutSplitter.h (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MINIKIN_LAYOUT_SPLITTER_H
18 #define MINIKIN_LAYOUT_SPLITTER_H
19 
20 #include "minikin/Layout.h"
21 
22 #include <memory>
23 
24 #include <unicode/ubidi.h>
25 
26 #include "minikin/Macros.h"
27 #include "minikin/U16StringPiece.h"
28 
29 #include "LayoutUtils.h"
30 
31 namespace minikin {
32 
33 // LayoutSplitter split the input text into recycle-able pieces.
34 //
35 // LayoutSplitter basically splits the text before and after space characters.
36 //
37 // Here is an example of how the LayoutSplitter split the text into layout pieces.
38 // Input:
39 //   Text          : T h i s _ i s _ a n _ e x a m p l e _ t e x t .
40 //   Range         :            |-------------------|
41 //
42 // Output:
43 //   Context Range :          |---|-|---|-|-------------|
44 //   Piece Range   :            |-|-|---|-|---------|
45 //
46 // Input:
47 //   Text          : T h i s _ i s _ a n _ e x a m p l e _ t e x t .
48 //   Range         :                          |-------|
49 //
50 // Output:
51 //   Context Range :                      |-------------|
52 //   Piece Range   :                          |-------|
53 class LayoutSplitter {
54 public:
LayoutSplitter(const U16StringPiece & textBuf,const Range & range,bool isRtl)55     LayoutSplitter(const U16StringPiece& textBuf, const Range& range, bool isRtl)
56             : mTextBuf(textBuf), mRange(range), mIsRtl(isRtl) {}
57 
58     class iterator {
59     public:
60         bool operator==(const iterator& o) const { return mPos == o.mPos && mParent == o.mParent; }
61 
62         bool operator!=(const iterator& o) const { return !(*this == o); }
63 
64         std::pair<Range, Range> operator*() const {
65             return std::make_pair(mContextRange, mPieceRange);
66         }
67 
68         iterator& operator++() {
69             const U16StringPiece& textBuf = mParent->mTextBuf;
70             const Range& range = mParent->mRange;
71             if (mParent->mIsRtl) {
72                 mPos = mPieceRange.getStart();
73                 mContextRange.setStart(getPrevWordBreakForCache(textBuf, mPos));
74                 mContextRange.setEnd(mPos);
75                 mPieceRange.setStart(std::max(mContextRange.getStart(), range.getStart()));
76                 mPieceRange.setEnd(mPos);
77             } else {
78                 mPos = mPieceRange.getEnd();
79                 mContextRange.setStart(mPos);
80                 mContextRange.setEnd(getNextWordBreakForCache(textBuf, mPos));
81                 mPieceRange.setStart(mPos);
82                 mPieceRange.setEnd(std::min(mContextRange.getEnd(), range.getEnd()));
83             }
84             return *this;
85         }
86 
87     private:
88         friend class LayoutSplitter;
89 
iterator(const LayoutSplitter * parent,uint32_t pos)90         iterator(const LayoutSplitter* parent, uint32_t pos) : mParent(parent), mPos(pos) {
91             const U16StringPiece& textBuf = mParent->mTextBuf;
92             const Range& range = mParent->mRange;
93             if (parent->mIsRtl) {
94                 mContextRange.setStart(getPrevWordBreakForCache(textBuf, pos));
95                 mContextRange.setEnd(getNextWordBreakForCache(textBuf, pos == 0 ? 0 : pos - 1));
96                 mPieceRange.setStart(std::max(mContextRange.getStart(), range.getStart()));
97                 mPieceRange.setEnd(pos);
98             } else {
99                 mContextRange.setStart(
100                         getPrevWordBreakForCache(textBuf, pos == range.getEnd() ? pos : pos + 1));
101                 mContextRange.setEnd(getNextWordBreakForCache(textBuf, pos));
102                 mPieceRange.setStart(pos);
103                 mPieceRange.setEnd(std::min(mContextRange.getEnd(), range.getEnd()));
104             }
105         }
106 
107         const LayoutSplitter* mParent;
108         uint32_t mPos;
109         Range mContextRange;
110         Range mPieceRange;
111     };
112 
begin()113     iterator begin() const { return iterator(this, mIsRtl ? mRange.getEnd() : mRange.getStart()); }
end()114     iterator end() const { return iterator(this, mIsRtl ? mRange.getStart() : mRange.getEnd()); }
115 
116 private:
117     U16StringPiece mTextBuf;
118     Range mRange;  // The range in the original buffer. Used for range check.
119     bool mIsRtl;   // The paragraph direction.
120 
121     MINIKIN_PREVENT_COPY_AND_ASSIGN(LayoutSplitter);
122 };
123 
124 }  // namespace minikin
125 
126 #endif  // MINIKIN_LAYOUT_SPLITTER_H
127