|  | /* | 
|  | * Copyright (C) 2013 Google Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions are | 
|  | * met: | 
|  | * | 
|  | *     * Redistributions of source code must retain the above copyright | 
|  | * notice, this list of conditions and the following disclaimer. | 
|  | *     * Redistributions in binary form must reproduce the above | 
|  | * copyright notice, this list of conditions and the following disclaimer | 
|  | * in the documentation and/or other materials provided with the | 
|  | * distribution. | 
|  | *     * Neither the name of Google Inc. nor the names of its | 
|  | * contributors may be used to endorse or promote products derived from | 
|  | * this software without specific prior written permission. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "core/rendering/AbstractInlineTextBox.h" | 
|  |  | 
|  | #include "core/editing/TextIterator.h" | 
|  | #include "platform/text/TextBreakIterator.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | AbstractInlineTextBox::InlineToAbstractInlineTextBoxHashMap* AbstractInlineTextBox::gAbstractInlineTextBoxMap = 0; | 
|  |  | 
|  | PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::getOrCreate(RenderText* renderText, InlineTextBox* inlineTextBox) | 
|  | { | 
|  | if (!inlineTextBox) | 
|  | return nullptr; | 
|  |  | 
|  | if (!gAbstractInlineTextBoxMap) | 
|  | gAbstractInlineTextBoxMap = new InlineToAbstractInlineTextBoxHashMap(); | 
|  |  | 
|  | InlineToAbstractInlineTextBoxHashMap::const_iterator it = gAbstractInlineTextBoxMap->find(inlineTextBox); | 
|  | if (it != gAbstractInlineTextBoxMap->end()) | 
|  | return it->value; | 
|  |  | 
|  | RefPtr<AbstractInlineTextBox> obj = adoptRef(new AbstractInlineTextBox(renderText, inlineTextBox)); | 
|  | gAbstractInlineTextBoxMap->set(inlineTextBox, obj); | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | void AbstractInlineTextBox::willDestroy(InlineTextBox* inlineTextBox) | 
|  | { | 
|  | if (!gAbstractInlineTextBoxMap) | 
|  | return; | 
|  |  | 
|  | InlineToAbstractInlineTextBoxHashMap::const_iterator it = gAbstractInlineTextBoxMap->find(inlineTextBox); | 
|  | if (it != gAbstractInlineTextBoxMap->end()) { | 
|  | it->value->detach(); | 
|  | gAbstractInlineTextBoxMap->remove(inlineTextBox); | 
|  | } | 
|  | } | 
|  |  | 
|  | void AbstractInlineTextBox::detach() | 
|  | { | 
|  | m_renderText = 0; | 
|  | m_inlineTextBox = 0; | 
|  | } | 
|  |  | 
|  | PassRefPtr<AbstractInlineTextBox> AbstractInlineTextBox::nextInlineTextBox() const | 
|  | { | 
|  | if (!m_inlineTextBox) | 
|  | return nullptr; | 
|  |  | 
|  | return getOrCreate(m_renderText, m_inlineTextBox->nextTextBox()); | 
|  | } | 
|  |  | 
|  | LayoutRect AbstractInlineTextBox::bounds() const | 
|  | { | 
|  | if (!m_inlineTextBox || !m_renderText) | 
|  | return LayoutRect(); | 
|  |  | 
|  | FloatRect boundaries = m_inlineTextBox->calculateBoundaries(); | 
|  | return m_renderText->localToAbsoluteQuad(boundaries).enclosingBoundingBox(); | 
|  | } | 
|  |  | 
|  | unsigned AbstractInlineTextBox::len() const | 
|  | { | 
|  | if (!m_inlineTextBox) | 
|  | return 0; | 
|  |  | 
|  | return m_inlineTextBox->len(); | 
|  | } | 
|  |  | 
|  | AbstractInlineTextBox::Direction AbstractInlineTextBox::direction() const | 
|  | { | 
|  | if (!m_inlineTextBox || !m_renderText) | 
|  | return LeftToRight; | 
|  |  | 
|  | if (m_renderText->style()->isHorizontalWritingMode()) | 
|  | return (m_inlineTextBox->direction() == RTL ? RightToLeft : LeftToRight); | 
|  | return (m_inlineTextBox->direction() == RTL ? BottomToTop : TopToBottom); | 
|  | } | 
|  |  | 
|  | void AbstractInlineTextBox::characterWidths(Vector<float>& widths) const | 
|  | { | 
|  | if (!m_inlineTextBox) | 
|  | return; | 
|  |  | 
|  | m_inlineTextBox->characterWidths(widths); | 
|  | } | 
|  |  | 
|  | void AbstractInlineTextBox::wordBoundaries(Vector<WordBoundaries>& words) const | 
|  | { | 
|  | if (!m_inlineTextBox) | 
|  | return; | 
|  |  | 
|  | String text = this->text(); | 
|  | int len = text.length(); | 
|  | TextBreakIterator* iterator = wordBreakIterator(text, 0, len); | 
|  |  | 
|  | // FIXME: When http://crbug.com/411764 is fixed, replace this with an ASSERT. | 
|  | if (!iterator) | 
|  | return; | 
|  |  | 
|  | int pos = iterator->first(); | 
|  | while (pos >= 0 && pos < len) { | 
|  | int next = iterator->next(); | 
|  | if (isWordTextBreak(iterator)) | 
|  | words.append(WordBoundaries(pos, next)); | 
|  | pos = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | String AbstractInlineTextBox::text() const | 
|  | { | 
|  | if (!m_inlineTextBox || !m_renderText) | 
|  | return String(); | 
|  |  | 
|  | unsigned start = m_inlineTextBox->start(); | 
|  | unsigned len = m_inlineTextBox->len(); | 
|  | if (Node* node = m_renderText->node()) { | 
|  | RefPtrWillBeRawPtr<Range> range = Range::create(node->document()); | 
|  | range->setStart(node, start, IGNORE_EXCEPTION); | 
|  | range->setEnd(node, start + len, IGNORE_EXCEPTION); | 
|  | return plainText(range.get(), TextIteratorIgnoresStyleVisibility); | 
|  | } | 
|  |  | 
|  | String result = m_renderText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace); | 
|  | if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace()) | 
|  | return result + " "; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | } // namespace blink |