1/*
2 * Copyright (C) 2017 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_ANDROID_LINE_BREAKER_HELPERS_H
18#define MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
19
20#include <algorithm>
21
22#include "minikin/LineBreaker.h"
23
24namespace minikin {
25namespace android {
26
27class AndroidLineWidth : public LineWidth {
28public:
29    AndroidLineWidth(float firstWidth, int32_t firstLineCount, float restWidth,
30                     const std::vector<float>& indents, const std::vector<float>& leftPaddings,
31                     const std::vector<float>& rightPaddings, int32_t indentsAndPaddingsOffset)
32            : mFirstWidth(firstWidth),
33              mFirstLineCount(firstLineCount),
34              mRestWidth(restWidth),
35              mIndents(indents),
36              mLeftPaddings(leftPaddings),
37              mRightPaddings(rightPaddings),
38              mOffset(indentsAndPaddingsOffset) {}
39
40    float getAt(size_t lineNo) const override {
41        const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount) ? mFirstWidth : mRestWidth;
42        return std::max(0.0f, width - get(mIndents, lineNo));
43    }
44
45    float getMin() const override {
46        // A simpler algorithm would have been simply looping until the larger of
47        // mFirstLineCount and mIndents.size()-mOffset, but that does unnecessary calculations
48        // when mFirstLineCount is large. Instead, we measure the first line, all the lines that
49        // have an indent, and the first line after firstWidth ends and restWidth starts.
50        float minWidth = std::min(getAt(0), getAt(mFirstLineCount));
51        for (size_t lineNo = 1; lineNo + mOffset < mIndents.size(); lineNo++) {
52            minWidth = std::min(minWidth, getAt(lineNo));
53        }
54        return minWidth;
55    }
56
57    float getLeftPaddingAt(size_t lineNo) const override { return get(mLeftPaddings, lineNo); }
58
59    float getRightPaddingAt(size_t lineNo) const override { return get(mRightPaddings, lineNo); }
60
61private:
62    float get(const std::vector<float>& vec, size_t lineNo) const {
63        if (vec.empty()) {
64            return 0;
65        }
66        const size_t index = lineNo + mOffset;
67        if (index < vec.size()) {
68            return vec[index];
69        } else {
70            return vec.back();
71        }
72    }
73
74    const float mFirstWidth;
75    const int32_t mFirstLineCount;
76    const float mRestWidth;
77    const std::vector<float>& mIndents;
78    const std::vector<float>& mLeftPaddings;
79    const std::vector<float>& mRightPaddings;
80    const int32_t mOffset;
81};
82
83class StaticLayoutNative {
84public:
85    StaticLayoutNative(BreakStrategy strategy, HyphenationFrequency frequency, bool isJustified,
86                       std::vector<float>&& indents, std::vector<float>&& leftPaddings,
87                       std::vector<float>&& rightPaddings)
88            : mStrategy(strategy),
89              mFrequency(frequency),
90              mIsJustified(isJustified),
91              mIndents(std::move(indents)),
92              mLeftPaddings(std::move(leftPaddings)),
93              mRightPaddings(std::move(rightPaddings)) {}
94
95    LineBreakResult computeBreaks(const U16StringPiece& textBuf, const MeasuredText& measuredText,
96                                  // Line width arguments
97                                  float firstWidth, int32_t firstWidthLineCount, float restWidth,
98                                  int32_t indentsOffset,
99                                  // Tab stop arguments
100                                  const int32_t* tabStops, int32_t tabStopSize,
101                                  int32_t defaultTabStopWidth) const {
102        AndroidLineWidth lineWidth(firstWidth, firstWidthLineCount, restWidth, mIndents,
103                                   mLeftPaddings, mRightPaddings, indentsOffset);
104        return breakIntoLines(textBuf, mStrategy, mFrequency, mIsJustified, measuredText, lineWidth,
105                              TabStops(tabStops, tabStopSize, defaultTabStopWidth));
106    }
107
108    inline BreakStrategy getStrategy() const { return mStrategy; }
109    inline HyphenationFrequency getFrequency() const { return mFrequency; }
110    inline bool isJustified() const { return mIsJustified; }
111
112private:
113    const BreakStrategy mStrategy;
114    const HyphenationFrequency mFrequency;
115    const bool mIsJustified;
116    const std::vector<float> mIndents;
117    const std::vector<float> mLeftPaddings;
118    const std::vector<float> mRightPaddings;
119};
120
121}  // namespace android
122}  // namespace minikin
123
124#endif  // MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
125