2 * (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Dirk Mueller (mueller@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
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.
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.
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.
24 #include "core/layout/LayoutTextFragment.h"
26 #include "core/dom/FirstLetterPseudoElement.h"
27 #include "core/dom/PseudoElement.h"
28 #include "core/dom/StyleChangeReason.h"
29 #include "core/dom/Text.h"
30 #include "core/layout/HitTestResult.h"
31 #include "core/layout/LayoutBlock.h"
35 LayoutTextFragment::LayoutTextFragment(Node
* node
, StringImpl
* str
, int startOffset
, int length
)
36 : LayoutText(node
, str
? str
->substring(startOffset
, length
) : PassRefPtr
<StringImpl
>(nullptr))
37 , m_start(startOffset
)
39 , m_isRemainingTextLayoutObject(false)
40 , m_contentString(str
)
41 , m_firstLetterPseudoElement(nullptr)
45 LayoutTextFragment::LayoutTextFragment(Node
* node
, StringImpl
* str
)
46 : LayoutText(node
, str
)
48 , m_end(str
? str
->length() : 0)
49 , m_isRemainingTextLayoutObject(false)
50 , m_contentString(str
)
51 , m_firstLetterPseudoElement(nullptr)
55 LayoutTextFragment::~LayoutTextFragment()
57 ASSERT(!m_firstLetterPseudoElement
);
60 void LayoutTextFragment::willBeDestroyed()
62 if (m_isRemainingTextLayoutObject
&& m_firstLetterPseudoElement
)
63 m_firstLetterPseudoElement
->setRemainingTextLayoutObject(nullptr);
64 m_firstLetterPseudoElement
= nullptr;
65 LayoutText::willBeDestroyed();
68 PassRefPtr
<StringImpl
> LayoutTextFragment::completeText() const
70 Text
* text
= associatedTextNode();
71 return text
? text
->dataImpl() : contentString();
74 void LayoutTextFragment::setContentString(StringImpl
* str
)
76 m_contentString
= str
;
80 PassRefPtr
<StringImpl
> LayoutTextFragment::originalText() const
82 RefPtr
<StringImpl
> result
= completeText();
85 return result
->substring(start(), end());
88 void LayoutTextFragment::setText(PassRefPtr
<StringImpl
> text
, bool force
)
90 LayoutText::setText(text
, force
);
95 // If we're the remaining text from a first letter then we have to tell the
96 // first letter pseudo element to reattach itself so it can re-calculate the
97 // correct first-letter settings.
98 if (isRemainingTextLayoutObject()) {
99 ASSERT(firstLetterPseudoElement());
100 firstLetterPseudoElement()->updateTextFragments();
104 void LayoutTextFragment::setTextFragment(PassRefPtr
<StringImpl
> text
, unsigned start
, unsigned length
)
106 LayoutText::setText(text
, false);
112 void LayoutTextFragment::transformText()
114 // Note, we have to call LayoutText::setText here because, if we use our
115 // version we will, potentially, screw up the first-letter settings where
116 // we only use portions of the string.
117 if (RefPtr
<StringImpl
> textToTransform
= originalText())
118 LayoutText::setText(textToTransform
.release(), true);
121 UChar
LayoutTextFragment::previousCharacter() const
124 StringImpl
* original
= completeText().get();
125 if (original
&& start() <= original
->length())
126 return (*original
)[start() - 1];
129 return LayoutText::previousCharacter();
132 // If this is the layoutObject for a first-letter pseudoNode then we have to look
133 // at the node for the remaining text to find our content.
134 Text
* LayoutTextFragment::associatedTextNode() const
136 Node
* node
= this->firstLetterPseudoElement();
137 if (m_isRemainingTextLayoutObject
|| !node
) {
138 // If we don't have a node, then we aren't part of a first-letter pseudo
139 // element, so use the actual node. Likewise, if we have a node, but
140 // we're the remainingTextLayoutObject for a pseudo element use the real
148 if (node
->isFirstLetterPseudoElement()) {
149 FirstLetterPseudoElement
* pseudo
= toFirstLetterPseudoElement(node
);
150 LayoutObject
* nextLayoutObject
= FirstLetterPseudoElement::firstLetterTextLayoutObject(*pseudo
);
151 if (!nextLayoutObject
)
153 node
= nextLayoutObject
->node();
155 return (node
&& node
->isTextNode()) ? toText(node
) : nullptr;
158 void LayoutTextFragment::updateHitTestResult(HitTestResult
& result
, const LayoutPoint
& point
)
160 if (result
.innerNode())
163 LayoutObject::updateHitTestResult(result
, point
);
165 // If we aren't part of a first-letter element, or if we
166 // are part of first-letter but we're the remaining text then return.
167 if (m_isRemainingTextLayoutObject
|| !firstLetterPseudoElement())
169 result
.setInnerNode(firstLetterPseudoElement());