1/* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "core/rendering/AbstractInlineTextBox.h" 33 34#include "core/editing/TextIterator.h" 35#include "platform/text/TextBreakIterator.h" 36 37namespace WebCore { 38 39AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap* AbstractInlineTextBox::gAbstractInlineTextBoxMap = 0; 40 41PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(RenderText* renderText, InlineTextBox* inlineTextBox) 42{ 43 if (!inlineTextBox) 44 return 0; 45 46 if (!gAbstractInlineTextBoxMap) 47 gAbstractInlineTextBoxMap = new InlineToAbstractInlineTextBoxHashMap(); 48 49 InlineToAbstractInlineTextBoxHashMap::const_iterator it = gAbstractInlineTextBoxMap->find(inlineTextBox); 50 if (it != gAbstractInlineTextBoxMap->end()) 51 return it->value; 52 53 RefPtr<AbstractInlineTextBox> obj = adoptRef(new AbstractInlineTextBox(renderText, inlineTextBox)); 54 gAbstractInlineTextBoxMap->set(inlineTextBox, obj); 55 return obj; 56} 57 58void AbstractInlineTextBox::willDestroy(InlineTextBox* inlineTextBox) 59{ 60 if (!gAbstractInlineTextBoxMap) 61 return; 62 63 InlineToAbstractInlineTextBoxHashMap::const_iterator it = gAbstractInlineTextBoxMap->find(inlineTextBox); 64 if (it != gAbstractInlineTextBoxMap->end()) { 65 it->value->detach(); 66 gAbstractInlineTextBoxMap->remove(inlineTextBox); 67 } 68} 69 70void AbstractInlineTextBox::detach() 71{ 72 m_renderText = 0; 73 m_inlineTextBox = 0; 74} 75 76PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextInlineTextBox() const 77{ 78 if (!m_inlineTextBox) 79 return 0; 80 81 return getOrCreate(m_renderText, m_inlineTextBox->nextTextBox()); 82} 83 84LayoutRect AbstractInlineTextBox::bounds() const 85{ 86 if (!m_inlineTextBox || !m_renderText) 87 return LayoutRect(); 88 89 FloatRect boundaries = m_inlineTextBox->calculateBoundaries(); 90 return m_renderText->localToAbsoluteQuad(boundaries).enclosingBoundingBox(); 91} 92 93unsigned AbstractInlineTextBox::start() const 94{ 95 if (!m_inlineTextBox) 96 return 0; 97 98 return m_inlineTextBox->start(); 99} 100 101unsigned AbstractInlineTextBox::len() const 102{ 103 if (!m_inlineTextBox) 104 return 0; 105 106 return m_inlineTextBox->len(); 107} 108 109AbstractInlineTextBox::Direction AbstractInlineTextBox::direction() const 110{ 111 if (!m_inlineTextBox || !m_renderText) 112 return LeftToRight; 113 114 if (m_renderText->style()->isHorizontalWritingMode()) 115 return (m_inlineTextBox->direction() == RTL ? RightToLeft : LeftToRight); 116 return (m_inlineTextBox->direction() == RTL ? BottomToTop : TopToBottom); 117} 118 119void AbstractInlineTextBox::characterWidths(Vector<float>& widths) const 120{ 121 if (!m_inlineTextBox) 122 return; 123 124 m_inlineTextBox->characterWidths(widths); 125} 126 127void AbstractInlineTextBox::wordBoundaries(Vector<WordBoundaries>& words) const 128{ 129 if (!m_inlineTextBox) 130 return; 131 132 String text = this->text(); 133 int len = text.length(); 134 TextBreakIterator* iterator = wordBreakIterator(text, 0, len); 135 int pos = iterator->first(); 136 while (pos >= 0 && pos < len) { 137 int next = iterator->next(); 138 if (isWordTextBreak(iterator)) 139 words.append(WordBoundaries(pos, next)); 140 pos = next; 141 } 142} 143 144String AbstractInlineTextBox::text() const 145{ 146 if (!m_inlineTextBox || !m_renderText) 147 return String(); 148 149 unsigned start = m_inlineTextBox->start(); 150 unsigned len = m_inlineTextBox->len(); 151 if (Node* node = m_renderText->node()) { 152 RefPtr<Range> range = Range::create(node->document()); 153 range->setStart(node, start, IGNORE_EXCEPTION); 154 range->setEnd(node, start + len, IGNORE_EXCEPTION); 155 return plainText(range.get(), TextIteratorIgnoresStyleVisibility); 156 } 157 158 String result = m_renderText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace); 159 if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace()) 160 return result + " "; 161 return result; 162} 163 164} // namespace WebCore 165