1/* 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved. 4 * Copyright (C) 2010 Google Inc. All rights reserved. 5 * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com> 6 * Copyright (C) 2013 Adobe Systems Inc. All right reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25#include "config.h" 26#include "LineBreaker.h" 27 28#include "BreakingContextInlineHeaders.h" 29#include "RenderCombineText.h" 30 31namespace WebCore { 32 33void LineBreaker::reset() 34{ 35 m_positionedObjects.clear(); 36 m_hyphenated = false; 37 m_clear = CNONE; 38} 39 40// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building 41// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned 42// elements quite right. In other words, we need to build this function's work into the normal line 43// object iteration process. 44// NB. this function will insert any floating elements that would otherwise 45// be skipped but it will not position them. 46void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo) 47{ 48 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) { 49 RenderObject& object = *iterator.renderer(); 50 if (object.isOutOfFlowPositioned()) 51 setStaticPositions(m_block, toRenderBox(object)); 52 else if (object.isFloating()) 53 m_block.insertFloatingObject(toRenderBox(object)); 54 iterator.increment(); 55 } 56} 57 58void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo, FloatingObject* lastFloatFromPreviousLine, LineWidth& width) 59{ 60 while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) { 61 RenderObject& object = *resolver.position().renderer(); 62 if (object.isOutOfFlowPositioned()) { 63 setStaticPositions(m_block, toRenderBox(object)); 64 if (object.style().isOriginalDisplayInlineType()) { 65 resolver.runs().addRun(new BidiRun(0, 1, object, resolver.context(), resolver.dir())); 66 lineInfo.incrementRunsFromLeadingWhitespace(); 67 } 68 } else if (object.isFloating()) 69 m_block.positionNewFloatOnLine(m_block.insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width); 70 else if (object.isText() && object.style().hasTextCombine() && object.isCombineText() && !toRenderCombineText(object).isCombined()) { 71 toRenderCombineText(object).combineText(); 72 if (toRenderCombineText(object).isCombined()) 73 continue; 74 } 75 resolver.increment(); 76 } 77 resolver.commitExplicitEmbedding(); 78} 79 80InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) 81{ 82 return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements); 83} 84 85InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) 86{ 87 reset(); 88 89 ASSERT(resolver.position().root() == &m_block); 90 91 bool appliedStartWidth = resolver.position().offset(); 92 93 LineWidth width(m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block.style())); 94 95 skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); 96 97 if (resolver.position().atEnd()) 98 return resolver.position(); 99 100 BreakingContext context(*this, resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block); 101 102 while (context.currentObject()) { 103 context.initializeForCurrentObject(); 104 if (context.currentObject()->isBR()) { 105 context.handleBR(m_clear); 106 } else if (context.currentObject()->isOutOfFlowPositioned()) { 107 context.handleOutOfFlowPositioned(m_positionedObjects); 108 } else if (context.currentObject()->isFloating()) { 109 context.handleFloat(); 110 } else if (context.currentObject()->isRenderInline()) { 111 context.handleEmptyInline(); 112 } else if (context.currentObject()->isReplaced()) { 113 context.handleReplaced(); 114 } else if (context.currentObject()->isText()) { 115 if (context.handleText(wordMeasurements, m_hyphenated, consecutiveHyphenatedLines)) { 116 // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return. 117 return context.lineBreak(); 118 } 119 } else if (context.currentObject()->isLineBreakOpportunity()) 120 context.commitLineBreakAtCurrentWidth(context.currentObject()); 121 else 122 ASSERT_NOT_REACHED(); 123 124 if (context.atEnd()) 125 return context.handleEndOfLine(); 126 127 context.commitAndUpdateLineBreakIfNeeded(); 128 129 if (context.atEnd()) 130 return context.handleEndOfLine(); 131 132 context.increment(); 133 } 134 135 context.clearLineBreakIfFitsOnLine(true); 136 137 return context.handleEndOfLine(); 138} 139 140} 141