101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien/*
201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * Copyright (C) 2015 The Android Open Source Project
301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien *
401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * Licensed under the Apache License, Version 2.0 (the "License");
501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * you may not use this file except in compliance with the License.
601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * You may obtain a copy of the License at
701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien *
801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien *      http://www.apache.org/licenses/LICENSE-2.0
901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien *
1001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * Unless required by applicable law or agreed to in writing, software
1101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * distributed under the License is distributed on an "AS IS" BASIS,
1201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * See the License for the specific language governing permissions and
1401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * limitations under the License.
1501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien */
1601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
1701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien/**
1801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * A module for breaking paragraphs into lines, supporting high quality
1901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien * hyphenation and justification.
2001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien */
2101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
2201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#ifndef MINIKIN_LINE_BREAKER_H
2301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#define MINIKIN_LINE_BREAKER_H
2401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
25728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader#include <gtest/gtest_prod.h>
2601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#include "unicode/brkiter.h"
2701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#include "unicode/locid.h"
2801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#include <cmath>
2901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#include <vector>
30728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader#include "minikin/FontCollection.h"
315cdad92c300a65cab89b172e952186f0c5870657Raph Levien#include "minikin/Hyphenator.h"
32728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader#include "minikin/MinikinFont.h"
3357b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien#include "minikin/WordBreaker.h"
3401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
3514e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
3601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
3701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levienenum BreakStrategy {
3801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    kBreakStrategy_Greedy = 0,
3901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    kBreakStrategy_HighQuality = 1,
4001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    kBreakStrategy_Balanced = 2
4101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien};
4201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
430dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournaderenum HyphenationFrequency {
440dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader    kHyphenationFrequency_None = 0,
450dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader    kHyphenationFrequency_Normal = 1,
460dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader    kHyphenationFrequency_Full = 2
470dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader};
480dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader
4901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien// TODO: want to generalize to be able to handle array of line widths
5001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levienclass LineWidths {
5101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    public:
5201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void setWidths(float firstWidth, int firstWidthLineCount, float restWidth) {
5301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mFirstWidth = firstWidth;
5401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mFirstWidthLineCount = firstWidthLineCount;
5501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mRestWidth = restWidth;
5601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
57bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien        void setIndents(const std::vector<float>& indents) {
58bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien            mIndents = indents;
59dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien        }
605cdad92c300a65cab89b172e952186f0c5870657Raph Levien        bool isConstant() const {
615cdad92c300a65cab89b172e952186f0c5870657Raph Levien            // technically mFirstWidthLineCount == 0 would count too, but doesn't actually happen
62bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien            return mRestWidth == mFirstWidth && mIndents.empty();
635cdad92c300a65cab89b172e952186f0c5870657Raph Levien        }
6401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float getLineWidth(int line) const {
65dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien            float width = (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
66bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien            if (!mIndents.empty()) {
67bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien                if ((size_t)line < mIndents.size()) {
68bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien                    width -= mIndents[line];
69dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien                } else {
70bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien                    width -= mIndents.back();
71dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien                }
72dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien            }
73dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien            return width;
7401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
75879e8a3a479b2cedd05e652f082683a02aa57dcfRaph Levien        void clear() {
76879e8a3a479b2cedd05e652f082683a02aa57dcfRaph Levien            mIndents.clear();
77879e8a3a479b2cedd05e652f082683a02aa57dcfRaph Levien        }
7801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    private:
7901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float mFirstWidth;
8001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        int mFirstWidthLineCount;
8101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float mRestWidth;
82bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien        std::vector<float> mIndents;
8301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien};
8401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
8501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levienclass TabStops {
8601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    public:
8701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void set(const int* stops, size_t nStops, int tabWidth) {
8801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            if (stops != nullptr) {
8901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien                mStops.assign(stops, stops + nStops);
9001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            } else {
9101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien                mStops.clear();
9201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            }
9301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mTabWidth = tabWidth;
9401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
9501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float nextTab(float widthSoFar) const {
9601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            for (size_t i = 0; i < mStops.size(); i++) {
9701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien                if (mStops[i] > widthSoFar) {
9801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien                    return mStops[i];
9901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien                }
10001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            }
10101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return floor(widthSoFar / mTabWidth + 1) * mTabWidth;
10201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
10301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    private:
10401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<int> mStops;
10501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        int mTabWidth;
10601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien};
10701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
10801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levienclass LineBreaker {
10901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    public:
1105cdad92c300a65cab89b172e952186f0c5870657Raph Levien        const static int kTab_Shift = 29;  // keep synchronized with TAB_MASK in StaticLayout.java
1115cdad92c300a65cab89b172e952186f0c5870657Raph Levien
11201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // Note: Locale persists across multiple invocations (it is not cleaned up by finish()),
11301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // explicitly to avoid the cost of creating ICU BreakIterator objects. It should always
11401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // be set on the first invocation, but callers are encouraged not to call again unless
11501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // locale has actually changed.
11601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // That logic could be here but it's better for performance that it's upstream because of
11701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // the cost of constructing and comparing the ICU Locale object.
1185cdad92c300a65cab89b172e952186f0c5870657Raph Levien        // Note: caller is responsible for managing lifetime of hyphenator
119728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader        void setLocales(const char* locales, const std::vector<Hyphenator*>& hyphenators);
12001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
12101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void resize(size_t size) {
12201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mTextBuf.resize(size);
12301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mCharWidths.resize(size);
12401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
12501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
12601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        size_t size() const {
12701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mTextBuf.size();
12801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
12901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
13001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        uint16_t* buffer() {
13101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mTextBuf.data();
13201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
13301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
13401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float* charWidths() {
13501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mCharWidths.data();
13601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
13701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
13801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // set text to current contents of buffer
13901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void setText();
14001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
14101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void setLineWidths(float firstWidth, int firstWidthLineCount, float restWidth);
14201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
143bb86b433f97a301c11800806b1ce5331fa227d4aRaph Levien        void setIndents(const std::vector<float>& indents);
144dc7bc6e39e1ef6b713b927baf24db8b4f02f1a3fRaph Levien
14501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void setTabStops(const int* stops, size_t nStops, int tabWidth) {
14601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            mTabStops.set(stops, nStops, tabWidth);
14701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
14801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
14901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        BreakStrategy getStrategy() const { return mStrategy; }
15001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
15101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void setStrategy(BreakStrategy strategy) { mStrategy = strategy; }
15201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
1533a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka        void setJustified(bool justified) { mJustified = justified; }
1543a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka
1550dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader        HyphenationFrequency getHyphenationFrequency() const { return mHyphenationFrequency; }
1560dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader
1570dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader        void setHyphenationFrequency(HyphenationFrequency frequency) {
1580dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader            mHyphenationFrequency = frequency;
1590dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader        }
1600dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader
16101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // TODO: this class is actually fairly close to being general and not tied to using
16201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // Minikin to do the shaping of the strings. The main thing that would need to be changed
16301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // is having some kind of callback (or virtual class, or maybe even template), which could
16401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // easily be instantiated with Minikin's Layout. Future work for when needed.
165dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        float addStyleRun(MinikinPaint* paint, const std::shared_ptr<FontCollection>& typeface,
166dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka                FontStyle style, size_t start, size_t end, bool isRtl);
16701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
16801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void addReplacement(size_t start, size_t end, float width);
16901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
17001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        size_t computeBreaks();
17101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
17201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        const int* getBreaks() const {
17301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mBreaks.data();
17401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
17501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
17601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        const float* getWidths() const {
17701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mWidths.data();
17801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
17901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
1805cdad92c300a65cab89b172e952186f0c5870657Raph Levien        const int* getFlags() const {
18101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            return mFlags.data();
18201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        }
18301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
18401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void finish();
18501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
18601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien    private:
18701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // ParaWidth is used to hold cumulative width from beginning of paragraph. Note that for
18801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // very large paragraphs, accuracy could degrade using only 32-bit float. Note however
18901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // that float is used extensively on the Java side for this. This is a typedef so that
19001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // we can easily change it based on performance/accuracy tradeoff.
19101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        typedef double ParaWidth;
19201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
19301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // A single candidate break
19401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        struct Candidate {
19501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            size_t offset;  // offset to text buffer, in code units
19601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            size_t prev;  // index to previous break
19767d1601c603970aecd737cf8b82f6a13648e0820Roozbeh Pournader            ParaWidth preBreak;  // width of text until this point, if we decide to not break here
19867d1601c603970aecd737cf8b82f6a13648e0820Roozbeh Pournader            ParaWidth postBreak;  // width of text until this point, if we decide to break here
19901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            float penalty;  // penalty of this break (for example, hyphen penalty)
20001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien            float score;  // best score found for this break
2015cdad92c300a65cab89b172e952186f0c5870657Raph Levien            size_t lineNumber;  // only updated for non-constant line widths
2023a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka            size_t preSpaceCount;  // preceding space count before breaking
2033a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka            size_t postSpaceCount;  // preceding space count after breaking
204c7ef4000c1e840c3d3b66e85a40ebd34a5a2a8eeRoozbeh Pournader            HyphenationType hyphenType;
20501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        };
20601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
20701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float currentLineWidth() const;
20801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
2093a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka        void addWordBreak(size_t offset, ParaWidth preBreak, ParaWidth postBreak,
210c7ef4000c1e840c3d3b66e85a40ebd34a5a2a8eeRoozbeh Pournader                size_t preSpaceCount, size_t postSpaceCount, float penalty, HyphenationType hyph);
21101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
21201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void addCandidate(Candidate cand);
21367d1601c603970aecd737cf8b82f6a13648e0820Roozbeh Pournader        void pushGreedyBreak();
21401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
2155cdad92c300a65cab89b172e952186f0c5870657Raph Levien        // push an actual break to the output. Takes care of setting flags for tab
216c7ef4000c1e840c3d3b66e85a40ebd34a5a2a8eeRoozbeh Pournader        void pushBreak(int offset, float width, uint8_t hyphenEdit);
2175cdad92c300a65cab89b172e952186f0c5870657Raph Levien
2183a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka        float getSpaceWidth() const;
2193a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka
22001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        void computeBreaksGreedy();
22101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
222abae97a39c26e191e350575932611a90e6b04d06Raph Levien        void computeBreaksOptimal(bool isRectangular);
2235cdad92c300a65cab89b172e952186f0c5870657Raph Levien
2245cdad92c300a65cab89b172e952186f0c5870657Raph Levien        void finishBreaksOptimal();
22501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
22657b6dae9894b9362ef04517ff477fd491f9d433bRaph Levien        WordBreaker mWordBreaker;
227c7ef4000c1e840c3d3b66e85a40ebd34a5a2a8eeRoozbeh Pournader        icu::Locale mLocale;
22801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<uint16_t>mTextBuf;
22901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<float>mCharWidths;
23001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
2315cdad92c300a65cab89b172e952186f0c5870657Raph Levien        Hyphenator* mHyphenator;
232c7ef4000c1e840c3d3b66e85a40ebd34a5a2a8eeRoozbeh Pournader        std::vector<HyphenationType> mHyphBuf;
2335cdad92c300a65cab89b172e952186f0c5870657Raph Levien
23401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // layout parameters
23501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        BreakStrategy mStrategy = kBreakStrategy_Greedy;
2360dc07c0be325b7c12c50729e04c4b2785a673fd7Roozbeh Pournader        HyphenationFrequency mHyphenationFrequency = kHyphenationFrequency_Normal;
2373a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka        bool mJustified;
23801f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        LineWidths mLineWidths;
23901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        TabStops mTabStops;
24001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
24101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // result of line breaking
24201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<int> mBreaks;
24301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<float> mWidths;
2445cdad92c300a65cab89b172e952186f0c5870657Raph Levien        std::vector<int> mFlags;
24501f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
24601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        ParaWidth mWidth = 0;
24701f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        std::vector<Candidate> mCandidates;
248abae97a39c26e191e350575932611a90e6b04d06Raph Levien        float mLinePenalty = 0.0f;
24901f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
25001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        // the following are state for greedy breaker (updated while adding style runs)
25101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        size_t mLastBreak;
25201f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        size_t mBestBreak;
25301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        float mBestScore;
25401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        ParaWidth mPreBreak;  // prebreak of last break
25567d1601c603970aecd737cf8b82f6a13648e0820Roozbeh Pournader        uint32_t mLastHyphenation;  // hyphen edit of last break kept for next line
25601f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien        int mFirstTabIndex;
2573a74bcd0b4c4150cd524a37cdfa4e0ffe490cca6Seigo Nonaka        size_t mSpaceCount;
258728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader
259728f42cbd5acd0fa8d8dbe07d0302d41475eb95cRoozbeh Pournader        FRIEND_TEST(LineBreakerTest, setLocales);
26001f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien};
26101f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
26214e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
26301f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien
26401f526614431e3a0a6e1a48039e00b8a9b7d6fbfRaph Levien#endif  // MINIKIN_LINE_BREAKER_H
265