17053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta/* 27053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 37053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * 47053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 57053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * you may not use this file except in compliance with the License. 67053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * You may obtain a copy of the License at 77053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * 87053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 97053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * 107053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 117053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 127053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * See the License for the specific language governing permissions and 147053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * limitations under the License. 157053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta */ 167053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 177053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptapackage android.text; 187053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 19476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull; 207053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport android.text.Primitive.PrimitiveType; 217053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport android.text.StaticLayout.LineBreaks; 227053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 237053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport java.util.ArrayList; 247053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport java.util.List; 257053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport java.util.ListIterator; 267053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 277053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptaimport static android.text.Primitive.PrimitiveType.PENALTY_INFINITY; 287053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 297053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 307053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta// Based on the native implementation of OptimizingLineBreaker in 317053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260 327053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta/** 337053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * A more complex version of line breaking where we try to prevent the right edge from being too 347053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * jagged. 357053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta */ 367053919a3a55ad1b58e6db701afda18850037732Deepanshu Guptapublic class OptimizingLineBreaker extends LineBreaker { 377053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 387053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth, 397053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @NonNull TabStops tabStops) { 407053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta super(primitives, lineWidth, tabStops); 417053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 427053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 437053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @Override 447053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta public void computeBreaks(@NonNull LineBreaks breakInfo) { 457053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int numBreaks = mPrimitives.size(); 467053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta assert numBreaks > 0; 477053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (numBreaks == 1) { 487053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // This can be true only if it's an empty paragraph. 497053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Primitive p = mPrimitives.get(0); 507053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta assert p.type == PrimitiveType.PENALTY; 517053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakInfo.breaks = new int[]{0}; 527053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakInfo.widths = new float[]{p.width}; 5326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien breakInfo.flags = new int[]{0}; 547053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return; 557053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 567053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Node[] opt = new Node[numBreaks]; 577053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta opt[0] = new Node(-1, 0, 0, 0, false); 587053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false); 597053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 607053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta ArrayList<Integer> active = new ArrayList<Integer>(); 617053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta active.add(0); 627053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int lastBreak = 0; 637053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta for (int i = 0; i < numBreaks; i++) { 647053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Primitive p = mPrimitives.get(i); 657053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.type == PrimitiveType.PENALTY) { 667053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta boolean finalBreak = (i + 1 == numBreaks); 677053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Node bestBreak = null; 687053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 697053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta for (ListIterator<Integer> it = active.listIterator(); it.hasNext(); 707053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /* incrementing done in loop */) { 717053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int pos = it.next(); 727053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int lines = opt[pos].mPrevCount; 737053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float maxWidth = mLineWidth.getLineWidth(lines); 747053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // we have to compute metrics every time -- 757053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // we can't really pre-compute this stuff and just deal with breaks 767053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // because of the way tab characters work, this makes it computationally 777053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // harder, but this way, we can still optimize while treating tab characters 787053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // correctly 797053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta LineMetrics lineMetrics = computeMetrics(pos, i); 807053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (lineMetrics.mPrintedWidth <= maxWidth) { 817053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth, 827053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta finalBreak, p.penalty) + opt[pos].mDemerits; 837053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (bestBreak == null || demerits < bestBreak.mDemerits) { 847053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (bestBreak == null) { 857053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits, 867053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineMetrics.mPrintedWidth, lineMetrics.mHasTabs); 877053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } else { 887053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak.mPrev = pos; 897053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak.mPrevCount = opt[pos].mPrevCount + 1; 907053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak.mDemerits = demerits; 917053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak.mWidth = lineMetrics.mPrintedWidth; 927053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta bestBreak.mHasTabs = lineMetrics.mHasTabs; 937053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 947053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 957053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } else { 967053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta it.remove(); 977053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 987053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 997053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.penalty == -PENALTY_INFINITY) { 1007053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta active.clear(); 1017053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1027053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (bestBreak != null) { 1037053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta opt[i] = bestBreak; 1047053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta active.add(i); 1057053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lastBreak = i; 1067053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1077053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (active.isEmpty()) { 1087053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // we can't give up! 1097053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta LineMetrics lineMetrics = new LineMetrics(); 1107053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int lines = opt[lastBreak].mPrevCount; 1117053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float maxWidth = mLineWidth.getLineWidth(lines); 1127053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics); 1137053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/, 1147053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineMetrics.mWidth, lineMetrics.mHasTabs); 1157053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta active.add(breakIndex); 1167053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lastBreak = breakIndex; 1177053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta i = breakIndex; // incremented by i++ 1187053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1197053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1207053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1217053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1227053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int idx = numBreaks - 1; 1237053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int count = opt[idx].mPrevCount; 1247053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta resize(breakInfo, count); 1257053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta while (opt[idx].mPrev != -1) { 1267053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta count--; 1277053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta assert count >=0; 1287053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1297053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakInfo.breaks[count] = mPrimitives.get(idx).location; 1307053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakInfo.widths[count] = opt[idx].mWidth; 13126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien breakInfo.flags [count] = opt[idx].mHasTabs ? TAB_MASK : 0; 1327053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta idx = opt[idx].mPrev; 1337053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1347053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1357053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1367053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private static void resize(LineBreaks lineBreaks, int size) { 1377053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (lineBreaks.breaks.length == size) { 1387053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return; 1397053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1407053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int[] breaks = new int[size]; 1417053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float[] widths = new float[size]; 14226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien int[] flags = new int[size]; 1437053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1447053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int toCopy = Math.min(size, lineBreaks.breaks.length); 1457053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy); 1467053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta System.arraycopy(lineBreaks.widths, 0, widths, 0, toCopy); 1477053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta System.arraycopy(lineBreaks.flags, 0, flags, 0, toCopy); 1487053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1497053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineBreaks.breaks = breaks; 1507053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineBreaks.widths = widths; 1517053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineBreaks.flags = flags; 1527053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1537053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1547053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @NonNull 1557053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private LineMetrics computeMetrics(int start, int end) { 1567053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta boolean f = false; 1577053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float w = 0, pw = 0; 1587053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta for (int i = start; i < end; i++) { 1597053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Primitive p = mPrimitives.get(i); 1607053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) { 1617053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta w += p.width; 1627053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.type == PrimitiveType.BOX) { 1637053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta pw = w; 1647053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1657053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } else if (p.type == PrimitiveType.VARIABLE) { 1667053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta w = mTabStops.width(w); 1677053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta f = true; 1687053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1697053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1707053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return new LineMetrics(w, pw, f); 1717053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1727053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1737053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private static float computeDemerits(float maxWidth, float width, boolean finalBreak, 1747053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float penalty) { 1757053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float deviation = finalBreak ? 0 : maxWidth - width; 1767053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return (deviation * deviation) + penalty; 1777053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1787053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1797053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /** 1807053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * @return the last break position or -1 if failed. 1817053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta */ 1827053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @SuppressWarnings("ConstantConditions") // method too complex to be analyzed. 1837053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private int desperateBreak(int start, int limit, float maxWidth, 1847053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @NonNull LineMetrics lineMetrics) { 1857053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float w = 0, pw = 0; 1867053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta boolean breakFound = false; 1877053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE; 1887053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta for (int i = start; i < limit; i++) { 1897053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta Primitive p = mPrimitives.get(i); 1907053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 1917053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) { 1927053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta w += p.width; 1937053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (p.type == PrimitiveType.BOX) { 1947053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta pw = w; 1957053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 1967053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } else if (p.type == PrimitiveType.VARIABLE) { 1977053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta w = mTabStops.width(w); 1987053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta firstTabIndex = Math.min(firstTabIndex, i); 1997053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2007053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2017053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (pw > maxWidth && breakFound) { 2027053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta break; 2037053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2047053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2057053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // must make progress 2067053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (i > start && 2077053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) { 2087053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakFound = true; 2097053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta breakIndex = i; 2107053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2117053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2127053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2137053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta if (breakFound) { 2147053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineMetrics.mWidth = w; 2157053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineMetrics.mPrintedWidth = pw; 2167053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex); 2177053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return breakIndex; 2187053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } else { 2197053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta return -1; 2207053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2217053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2227053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2237053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private static class LineMetrics { 2247053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /** Actual width of the line. */ 2257053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float mWidth; 2267053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /** Width of the line minus trailing whitespace. */ 2277053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float mPrintedWidth; 2287053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta boolean mHasTabs; 2297053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2307053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta public LineMetrics() { 2317053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2327053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2337053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta public LineMetrics(float width, float printedWidth, boolean hasTabs) { 2347053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mWidth = width; 2357053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mPrintedWidth = printedWidth; 2367053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mHasTabs = hasTabs; 2377053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2387053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2397053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2407053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /** 2417053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta * A struct to store the info about a break. 2427053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta */ 2437053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta @SuppressWarnings("SpellCheckingInspection") // For the word struct. 2447053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta private static class Node { 2457053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // -1 for the first node. 2467053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int mPrev; 2477053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta // number of breaks so far. 2487053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta int mPrevCount; 2497053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float mDemerits; 2507053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta float mWidth; 2517053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta boolean mHasTabs; 2527053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta 2537053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) { 2547053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mPrev = prev; 2557053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mPrevCount = prevCount; 2567053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mDemerits = demerits; 2577053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mWidth = width; 2587053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta mHasTabs = hasTabs; 2597053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2607053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta } 2617053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta} 262