Home | History | Annotate | Download | only in rendering
      1 /*
      2  * (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  * (C) 2000 Dirk Mueller (mueller (at) kde.org)
      4  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  *
     21  */
     22 
     23 #include "config.h"
     24 #include "core/rendering/RenderTextFragment.h"
     25 
     26 #include "core/dom/Text.h"
     27 #include "core/rendering/HitTestResult.h"
     28 #include "core/rendering/RenderBlock.h"
     29 
     30 namespace blink {
     31 
     32 RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOffset, int length)
     33     : RenderText(node, str ? str->substring(startOffset, length) : PassRefPtr<StringImpl>(nullptr))
     34     , m_start(startOffset)
     35     , m_end(length)
     36     , m_firstLetter(nullptr)
     37 {
     38 }
     39 
     40 RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str)
     41     : RenderText(node, str)
     42     , m_start(0)
     43     , m_end(str ? str->length() : 0)
     44     , m_contentString(str)
     45     , m_firstLetter(nullptr)
     46 {
     47 }
     48 
     49 RenderTextFragment::~RenderTextFragment()
     50 {
     51 }
     52 
     53 void RenderTextFragment::trace(Visitor* visitor)
     54 {
     55     visitor->trace(m_firstLetter);
     56     RenderText::trace(visitor);
     57 }
     58 
     59 RenderText* RenderTextFragment::firstRenderTextInFirstLetter() const
     60 {
     61     for (RenderObject* current = m_firstLetter; current; current = current->nextInPreOrder(m_firstLetter)) {
     62         if (current->isText())
     63             return toRenderText(current);
     64     }
     65     return 0;
     66 }
     67 
     68 PassRefPtr<StringImpl> RenderTextFragment::originalText() const
     69 {
     70     Node* e = node();
     71     RefPtr<StringImpl> result = ((e && e->isTextNode()) ? toText(e)->dataImpl() : contentString());
     72     if (!result)
     73         return nullptr;
     74     return result->substring(start(), end());
     75 }
     76 
     77 void RenderTextFragment::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
     78 {
     79     RenderText::styleDidChange(diff, oldStyle);
     80 
     81     if (RenderBlock* block = blockForAccompanyingFirstLetter()) {
     82         block->style()->removeCachedPseudoStyle(FIRST_LETTER);
     83         block->updateFirstLetter();
     84     }
     85 }
     86 
     87 void RenderTextFragment::willBeDestroyed()
     88 {
     89     if (m_firstLetter)
     90         m_firstLetter->destroy();
     91     RenderText::willBeDestroyed();
     92 }
     93 
     94 void RenderTextFragment::setText(PassRefPtr<StringImpl> text, bool force)
     95 {
     96     RenderText::setText(text, force);
     97 
     98     m_start = 0;
     99     m_end = textLength();
    100     if (m_firstLetter) {
    101         // FIXME: We should not modify the structure of the render tree during
    102         // layout. crbug.com/370458
    103         DeprecatedDisableModifyRenderTreeStructureAsserts disabler;
    104 
    105         ASSERT(!m_contentString);
    106         m_firstLetter->destroy();
    107         m_firstLetter = nullptr;
    108         if (Node* t = node()) {
    109             ASSERT(!t->renderer());
    110             t->setRenderer(this);
    111         }
    112     }
    113 }
    114 
    115 void RenderTextFragment::transformText()
    116 {
    117     // Don't reset first-letter here because we are only transforming the truncated fragment.
    118     if (RefPtr<StringImpl> textToTransform = originalText())
    119         RenderText::setText(textToTransform.release(), true);
    120 }
    121 
    122 UChar RenderTextFragment::previousCharacter() const
    123 {
    124     if (start()) {
    125         Node* e = node();
    126         StringImpl* original = ((e && e->isTextNode()) ? toText(e)->dataImpl() : contentString());
    127         if (original && start() <= original->length())
    128             return (*original)[start() - 1];
    129     }
    130 
    131     return RenderText::previousCharacter();
    132 }
    133 
    134 RenderBlock* RenderTextFragment::blockForAccompanyingFirstLetter() const
    135 {
    136     if (!m_firstLetter)
    137         return 0;
    138     for (RenderObject* block = m_firstLetter->parent(); block; block = block->parent()) {
    139         if (block->style()->hasPseudoStyle(FIRST_LETTER) && block->canHaveChildren() && block->isRenderBlock())
    140             return toRenderBlock(block);
    141     }
    142     return 0;
    143 }
    144 
    145 void RenderTextFragment::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
    146 {
    147     if (result.innerNode())
    148         return;
    149 
    150     RenderObject::updateHitTestResult(result, point);
    151     if (m_firstLetter || !node())
    152         return;
    153     RenderObject* nodeRenderer = node()->renderer();
    154     if (!nodeRenderer || !nodeRenderer->isText() || !toRenderText(nodeRenderer)->isTextFragment())
    155         return;
    156 
    157     if (isDescendantOf(toRenderTextFragment(nodeRenderer)->m_firstLetter))
    158         result.setIsFirstLetter(true);
    159 }
    160 
    161 } // namespace blink
    162