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 37 namespace blink { 38 39 AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap* AbstractInlineTextBox::gAbstractInlineTextBoxMap = 0; 40 41 PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(RenderText* renderText, InlineTextBox* inlineTextBox) 42 { 43 if (!inlineTextBox) 44 return nullptr; 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 58 void 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 70 void AbstractInlineTextBox::detach() 71 { 72 m_renderText = 0; 73 m_inlineTextBox = 0; 74 } 75 76 PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextInlineTextBox() const 77 { 78 if (!m_inlineTextBox) 79 return nullptr; 80 81 return getOrCreate(m_renderText, m_inlineTextBox->nextTextBox()); 82 } 83 84 LayoutRect 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 93 unsigned AbstractInlineTextBox::start() const 94 { 95 if (!m_inlineTextBox) 96 return 0; 97 98 return m_inlineTextBox->start(); 99 } 100 101 unsigned AbstractInlineTextBox::len() const 102 { 103 if (!m_inlineTextBox) 104 return 0; 105 106 return m_inlineTextBox->len(); 107 } 108 109 AbstractInlineTextBox::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 119 void AbstractInlineTextBox::characterWidths(Vector<float>& widths) const 120 { 121 if (!m_inlineTextBox) 122 return; 123 124 m_inlineTextBox->characterWidths(widths); 125 } 126 127 void 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 136 // FIXME: When http://crbug.com/411764 is fixed, replace this with an ASSERT. 137 if (!iterator) 138 return; 139 140 int pos = iterator->first(); 141 while (pos >= 0 && pos < len) { 142 int next = iterator->next(); 143 if (isWordTextBreak(iterator)) 144 words.append(WordBoundaries(pos, next)); 145 pos = next; 146 } 147 } 148 149 String AbstractInlineTextBox::text() const 150 { 151 if (!m_inlineTextBox || !m_renderText) 152 return String(); 153 154 unsigned start = m_inlineTextBox->start(); 155 unsigned len = m_inlineTextBox->len(); 156 if (Node* node = m_renderText->node()) { 157 RefPtrWillBeRawPtr<Range> range = Range::create(node->document()); 158 range->setStart(node, start, IGNORE_EXCEPTION); 159 range->setEnd(node, start + len, IGNORE_EXCEPTION); 160 return plainText(range.get(), TextIteratorIgnoresStyleVisibility); 161 } 162 163 String result = m_renderText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace); 164 if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace()) 165 return result + " "; 166 return result; 167 } 168 169 } // namespace blink 170