OptimizingLineBreaker.java revision 4ef9b507c2c1b73805533a86d935d637493d5903
14ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta/* 24ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 34ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * 44ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 54ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * you may not use this file except in compliance with the License. 64ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * You may obtain a copy of the License at 74ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * 84ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 94ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * 104ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 114ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 124ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * See the License for the specific language governing permissions and 144ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * limitations under the License. 154ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta */ 164ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 174ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptapackage android.text; 184ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 194ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport com.android.annotations.NonNull; 204ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 214ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport android.text.Primitive.PrimitiveType; 224ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport android.text.StaticLayout.LineBreaks; 234ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 244ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.ArrayList; 254ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.List; 264ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.ListIterator; 274ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 284ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport static android.text.Primitive.PrimitiveType.PENALTY_INFINITY; 294ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 304ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 314ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta// Based on the native implementation of OptimizingLineBreaker in 324ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260 334ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta/** 344ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * A more complex version of line breaking where we try to prevent the right edge from being too 354ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * jagged. 364ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta */ 374ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptapublic class OptimizingLineBreaker extends LineBreaker { 384ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 394ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth, 404ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @NonNull TabStops tabStops) { 414ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta super(primitives, lineWidth, tabStops); 424ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 434ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 444ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @Override 454ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta public void computeBreaks(@NonNull LineBreaks breakInfo) { 464ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int numBreaks = mPrimitives.size(); 474ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta assert numBreaks > 0; 484ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (numBreaks == 1) { 494ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // This can be true only if it's an empty paragraph. 504ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Primitive p = mPrimitives.get(0); 514ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta assert p.type == PrimitiveType.PENALTY; 524ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.breaks = new int[]{0}; 534ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.widths = new float[]{p.width}; 544ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.flags = new boolean[]{false}; 554ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return; 564ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 574ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Node[] opt = new Node[numBreaks]; 584ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta opt[0] = new Node(-1, 0, 0, 0, false); 594ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false); 604ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 614ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta ArrayList<Integer> active = new ArrayList<Integer>(); 624ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta active.add(0); 634ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int lastBreak = 0; 644ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta for (int i = 0; i < numBreaks; i++) { 654ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Primitive p = mPrimitives.get(i); 664ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.type == PrimitiveType.PENALTY) { 674ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean finalBreak = (i + 1 == numBreaks); 684ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Node bestBreak = null; 694ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 704ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta for (ListIterator<Integer> it = active.listIterator(); it.hasNext(); 714ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /* incrementing done in loop */) { 724ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int pos = it.next(); 734ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int lines = opt[pos].mPrevCount; 744ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float maxWidth = mLineWidth.getLineWidth(lines); 754ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // we have to compute metrics every time -- 764ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // we can't really pre-compute this stuff and just deal with breaks 774ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // because of the way tab characters work, this makes it computationally 784ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // harder, but this way, we can still optimize while treating tab characters 794ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // correctly 804ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta LineMetrics lineMetrics = computeMetrics(pos, i); 814ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (lineMetrics.mPrintedWidth <= maxWidth) { 824ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth, 834ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta finalBreak, p.penalty) + opt[pos].mDemerits; 844ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (bestBreak == null || demerits < bestBreak.mDemerits) { 854ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (bestBreak == null) { 864ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits, 874ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineMetrics.mPrintedWidth, lineMetrics.mHasTabs); 884ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else { 894ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak.mPrev = pos; 904ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak.mPrevCount = opt[pos].mPrevCount + 1; 914ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak.mDemerits = demerits; 924ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak.mWidth = lineMetrics.mPrintedWidth; 934ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta bestBreak.mHasTabs = lineMetrics.mHasTabs; 944ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 954ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 964ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else { 974ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta it.remove(); 984ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 994ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1004ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.penalty == -PENALTY_INFINITY) { 1014ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta active.clear(); 1024ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1034ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (bestBreak != null) { 1044ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta opt[i] = bestBreak; 1054ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta active.add(i); 1064ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lastBreak = i; 1074ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1084ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (active.isEmpty()) { 1094ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // we can't give up! 1104ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta LineMetrics lineMetrics = new LineMetrics(); 1114ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int lines = opt[lastBreak].mPrevCount; 1124ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float maxWidth = mLineWidth.getLineWidth(lines); 1134ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics); 1144ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/, 1154ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineMetrics.mWidth, lineMetrics.mHasTabs); 1164ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta active.add(breakIndex); 1174ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lastBreak = breakIndex; 1184ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta i = breakIndex; // incremented by i++ 1194ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1204ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1214ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1224ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1234ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int idx = numBreaks - 1; 1244ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int count = opt[idx].mPrevCount; 1254ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta resize(breakInfo, count); 1264ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta while (opt[idx].mPrev != -1) { 1274ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta count--; 1284ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta assert count >=0; 1294ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1304ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.breaks[count] = mPrimitives.get(idx).location; 1314ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.widths[count] = opt[idx].mWidth; 1324ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakInfo.flags [count] = opt[idx].mHasTabs; 1334ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta idx = opt[idx].mPrev; 1344ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1354ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1364ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1374ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static void resize(LineBreaks lineBreaks, int size) { 1384ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (lineBreaks.breaks.length == size) { 1394ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return; 1404ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1414ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int[] breaks = new int[size]; 1424ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float[] widths = new float[size]; 1434ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean[] flags = new boolean[size]; 1444ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1454ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int toCopy = Math.min(size, lineBreaks.breaks.length); 1464ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy); 1474ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta System.arraycopy(lineBreaks.widths, 0, widths, 0, toCopy); 1484ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta System.arraycopy(lineBreaks.flags, 0, flags, 0, toCopy); 1494ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1504ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaks.breaks = breaks; 1514ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaks.widths = widths; 1524ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaks.flags = flags; 1534ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1544ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1554ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @NonNull 1564ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private LineMetrics computeMetrics(int start, int end) { 1574ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean f = false; 1584ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float w = 0, pw = 0; 1594ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta for (int i = start; i < end; i++) { 1604ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Primitive p = mPrimitives.get(i); 1614ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) { 1624ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta w += p.width; 1634ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.type == PrimitiveType.BOX) { 1644ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta pw = w; 1654ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1664ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else if (p.type == PrimitiveType.VARIABLE) { 1674ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta w = mTabStops.width(w); 1684ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta f = true; 1694ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1704ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1714ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return new LineMetrics(w, pw, f); 1724ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1734ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1744ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static float computeDemerits(float maxWidth, float width, boolean finalBreak, 1754ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float penalty) { 1764ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float deviation = finalBreak ? 0 : maxWidth - width; 1774ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return (deviation * deviation) + penalty; 1784ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1794ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1804ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /** 1814ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * @return the last break position or -1 if failed. 1824ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta */ 1834ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @SuppressWarnings("ConstantConditions") // method too complex to be analyzed. 1844ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private int desperateBreak(int start, int limit, float maxWidth, 1854ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @NonNull LineMetrics lineMetrics) { 1864ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float w = 0, pw = 0; 1874ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean breakFound = false; 1884ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE; 1894ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta for (int i = start; i < limit; i++) { 1904ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Primitive p = mPrimitives.get(i); 1914ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 1924ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) { 1934ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta w += p.width; 1944ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (p.type == PrimitiveType.BOX) { 1954ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta pw = w; 1964ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 1974ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else if (p.type == PrimitiveType.VARIABLE) { 1984ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta w = mTabStops.width(w); 1994ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta firstTabIndex = Math.min(firstTabIndex, i); 2004ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2014ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2024ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (pw > maxWidth && breakFound) { 2034ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta break; 2044ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2054ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2064ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // must make progress 2074ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (i > start && 2084ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) { 2094ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakFound = true; 2104ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakIndex = i; 2114ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2124ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2134ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2144ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (breakFound) { 2154ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineMetrics.mWidth = w; 2164ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineMetrics.mPrintedWidth = pw; 2174ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex); 2184ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return breakIndex; 2194ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else { 2204ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return -1; 2214ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2224ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2234ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2244ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static class LineMetrics { 2254ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /** Actual width of the line. */ 2264ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float mWidth; 2274ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /** Width of the line minus trailing whitespace. */ 2284ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float mPrintedWidth; 2294ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean mHasTabs; 2304ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2314ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta public LineMetrics() { 2324ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2334ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2344ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta public LineMetrics(float width, float printedWidth, boolean hasTabs) { 2354ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mWidth = width; 2364ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mPrintedWidth = printedWidth; 2374ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mHasTabs = hasTabs; 2384ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2394ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2404ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2414ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /** 2424ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * A struct to store the info about a break. 2434ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta */ 2444ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @SuppressWarnings("SpellCheckingInspection") // For the word struct. 2454ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static class Node { 2464ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // -1 for the first node. 2474ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int mPrev; 2484ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // number of breaks so far. 2494ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int mPrevCount; 2504ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float mDemerits; 2514ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta float mWidth; 2524ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta boolean mHasTabs; 2534ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 2544ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) { 2554ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mPrev = prev; 2564ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mPrevCount = prevCount; 2574ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mDemerits = demerits; 2584ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mWidth = width; 2594ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta mHasTabs = hasTabs; 2604ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2614ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 2624ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta} 263