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