| OLD | NEW |
| 1 /* | 1 /* |
| 2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 2000 Dirk Mueller (mueller@kde.org) | 3 * (C) 2000 Dirk Mueller (mueller@kde.org) |
| 4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
| 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
| 6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) | 6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 12 * | 12 * |
| 13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
| 17 * | 17 * |
| 18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
| 19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
| 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
| 22 * | 22 * |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 #include "core/rendering/RenderText.h" | 26 #include "core/layout/LayoutText.h" |
| 27 | 27 |
| 28 #include "core/dom/AXObjectCache.h" | 28 #include "core/dom/AXObjectCache.h" |
| 29 #include "core/dom/Text.h" | 29 #include "core/dom/Text.h" |
| 30 #include "core/editing/VisiblePosition.h" | 30 #include "core/editing/VisiblePosition.h" |
| 31 #include "core/editing/iterators/TextIterator.h" | 31 #include "core/editing/iterators/TextIterator.h" |
| 32 #include "core/frame/FrameView.h" | 32 #include "core/frame/FrameView.h" |
| 33 #include "core/frame/Settings.h" | 33 #include "core/frame/Settings.h" |
| 34 #include "core/html/parser/TextResourceDecoder.h" | 34 #include "core/html/parser/TextResourceDecoder.h" |
| 35 #include "core/layout/Layer.h" | 35 #include "core/layout/Layer.h" |
| 36 #include "core/layout/LayoutBlock.h" | 36 #include "core/layout/LayoutBlock.h" |
| 37 #include "core/layout/LayoutTextCombine.h" |
| 37 #include "core/layout/LayoutView.h" | 38 #include "core/layout/LayoutView.h" |
| 38 #include "core/layout/TextRunConstructor.h" | 39 #include "core/layout/TextRunConstructor.h" |
| 39 #include "core/layout/line/AbstractInlineTextBox.h" | 40 #include "core/layout/line/AbstractInlineTextBox.h" |
| 40 #include "core/layout/line/EllipsisBox.h" | 41 #include "core/layout/line/EllipsisBox.h" |
| 41 #include "core/layout/line/InlineTextBox.h" | 42 #include "core/layout/line/InlineTextBox.h" |
| 42 #include "core/rendering/RenderCombineText.h" | |
| 43 #include "platform/fonts/Character.h" | 43 #include "platform/fonts/Character.h" |
| 44 #include "platform/fonts/FontCache.h" | 44 #include "platform/fonts/FontCache.h" |
| 45 #include "platform/geometry/FloatQuad.h" | 45 #include "platform/geometry/FloatQuad.h" |
| 46 #include "platform/graphics/paint/DisplayItemList.h" | 46 #include "platform/graphics/paint/DisplayItemList.h" |
| 47 #include "platform/text/BidiResolver.h" | 47 #include "platform/text/BidiResolver.h" |
| 48 #include "platform/text/TextBreakIterator.h" | 48 #include "platform/text/TextBreakIterator.h" |
| 49 #include "platform/text/TextRunIterator.h" | 49 #include "platform/text/TextRunIterator.h" |
| 50 #include "wtf/text/StringBuffer.h" | 50 #include "wtf/text/StringBuffer.h" |
| 51 #include "wtf/text/StringBuilder.h" | 51 #include "wtf/text/StringBuilder.h" |
| 52 #include "wtf/unicode/CharacterNames.h" | 52 #include "wtf/unicode/CharacterNames.h" |
| 53 | 53 |
| 54 using namespace WTF; | 54 using namespace WTF; |
| 55 using namespace Unicode; | 55 using namespace Unicode; |
| 56 | 56 |
| 57 namespace blink { | 57 namespace blink { |
| 58 | 58 |
| 59 struct SameSizeAsRenderText : public LayoutObject { | 59 struct SameSizeAsRenderText : public LayoutObject { |
| 60 uint32_t bitfields : 16; | 60 uint32_t bitfields : 16; |
| 61 float widths[4]; | 61 float widths[4]; |
| 62 String text; | 62 String text; |
| 63 void* pointers[2]; | 63 void* pointers[2]; |
| 64 }; | 64 }; |
| 65 | 65 |
| 66 static_assert(sizeof(RenderText) == sizeof(SameSizeAsRenderText), "RenderText sh
ould stay small"); | 66 static_assert(sizeof(LayoutText) == sizeof(SameSizeAsRenderText), "LayoutText sh
ould stay small"); |
| 67 | 67 |
| 68 class SecureTextTimer; | 68 class SecureTextTimer; |
| 69 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap; | 69 typedef HashMap<LayoutText*, SecureTextTimer*> SecureTextTimerMap; |
| 70 static SecureTextTimerMap* gSecureTextTimers = 0; | 70 static SecureTextTimerMap* gSecureTextTimers = 0; |
| 71 | 71 |
| 72 class SecureTextTimer final : public TimerBase { | 72 class SecureTextTimer final : public TimerBase { |
| 73 public: | 73 public: |
| 74 SecureTextTimer(RenderText* renderText) | 74 SecureTextTimer(LayoutText* renderText) |
| 75 : m_renderText(renderText) | 75 : m_renderText(renderText) |
| 76 , m_lastTypedCharacterOffset(-1) | 76 , m_lastTypedCharacterOffset(-1) |
| 77 { | 77 { |
| 78 } | 78 } |
| 79 | 79 |
| 80 void restartWithNewText(unsigned lastTypedCharacterOffset) | 80 void restartWithNewText(unsigned lastTypedCharacterOffset) |
| 81 { | 81 { |
| 82 m_lastTypedCharacterOffset = lastTypedCharacterOffset; | 82 m_lastTypedCharacterOffset = lastTypedCharacterOffset; |
| 83 if (Settings* settings = m_renderText->document().settings()) | 83 if (Settings* settings = m_renderText->document().settings()) |
| 84 startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE); | 84 startOneShot(settings->passwordEchoDurationInSeconds(), FROM_HERE); |
| 85 } | 85 } |
| 86 void invalidate() { m_lastTypedCharacterOffset = -1; } | 86 void invalidate() { m_lastTypedCharacterOffset = -1; } |
| 87 unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; } | 87 unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; } |
| 88 | 88 |
| 89 private: | 89 private: |
| 90 virtual void fired() override | 90 virtual void fired() override |
| 91 { | 91 { |
| 92 ASSERT(gSecureTextTimers->contains(m_renderText)); | 92 ASSERT(gSecureTextTimers->contains(m_renderText)); |
| 93 m_renderText->setText(m_renderText->text().impl(), true /* forcing setti
ng text as it may be masked later */); | 93 m_renderText->setText(m_renderText->text().impl(), true /* forcing setti
ng text as it may be masked later */); |
| 94 } | 94 } |
| 95 | 95 |
| 96 RenderText* m_renderText; | 96 LayoutText* m_renderText; |
| 97 int m_lastTypedCharacterOffset; | 97 int m_lastTypedCharacterOffset; |
| 98 }; | 98 }; |
| 99 | 99 |
| 100 static void makeCapitalized(String* string, UChar previous) | 100 static void makeCapitalized(String* string, UChar previous) |
| 101 { | 101 { |
| 102 if (string->isNull()) | 102 if (string->isNull()) |
| 103 return; | 103 return; |
| 104 | 104 |
| 105 unsigned length = string->length(); | 105 unsigned length = string->length(); |
| 106 const StringImpl& input = *string->impl(); | 106 const StringImpl& input = *string->impl(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 130 for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord =
endOfWord, endOfWord = boundary->next()) { | 130 for (endOfWord = boundary->next(); endOfWord != TextBreakDone; startOfWord =
endOfWord, endOfWord = boundary->next()) { |
| 131 if (startOfWord) // Ignore first char of previous string | 131 if (startOfWord) // Ignore first char of previous string |
| 132 result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace
: toTitleCase(stringWithPrevious[startOfWord])); | 132 result.append(input[startOfWord - 1] == noBreakSpace ? noBreakSpace
: toTitleCase(stringWithPrevious[startOfWord])); |
| 133 for (int i = startOfWord + 1; i < endOfWord; i++) | 133 for (int i = startOfWord + 1; i < endOfWord; i++) |
| 134 result.append(input[i - 1]); | 134 result.append(input[i - 1]); |
| 135 } | 135 } |
| 136 | 136 |
| 137 *string = result.toString(); | 137 *string = result.toString(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str) | 140 LayoutText::LayoutText(Node* node, PassRefPtr<StringImpl> str) |
| 141 : LayoutObject(!node || node->isDocumentNode() ? 0 : node) | 141 : LayoutObject(!node || node->isDocumentNode() ? 0 : node) |
| 142 , m_hasTab(false) | 142 , m_hasTab(false) |
| 143 , m_linesDirty(false) | 143 , m_linesDirty(false) |
| 144 , m_containsReversedText(false) | 144 , m_containsReversedText(false) |
| 145 , m_knownToHaveNoOverflowAndNoFallbackFonts(false) | 145 , m_knownToHaveNoOverflowAndNoFallbackFonts(false) |
| 146 , m_minWidth(-1) | 146 , m_minWidth(-1) |
| 147 , m_maxWidth(-1) | 147 , m_maxWidth(-1) |
| 148 , m_firstLineMinWidth(0) | 148 , m_firstLineMinWidth(0) |
| 149 , m_lastLineLineMinWidth(0) | 149 , m_lastLineLineMinWidth(0) |
| 150 , m_text(str) | 150 , m_text(str) |
| 151 , m_firstTextBox(0) | 151 , m_firstTextBox(0) |
| 152 , m_lastTextBox(0) | 152 , m_lastTextBox(0) |
| 153 { | 153 { |
| 154 ASSERT(m_text); | 154 ASSERT(m_text); |
| 155 // FIXME: Some clients of RenderText (and subclasses) pass Document as node
to create anonymous renderer. | 155 // FIXME: Some clients of LayoutText (and subclasses) pass Document as node
to create anonymous renderer. |
| 156 // They should be switched to passing null and using setDocumentForAnonymous
. | 156 // They should be switched to passing null and using setDocumentForAnonymous
. |
| 157 if (node && node->isDocumentNode()) | 157 if (node && node->isDocumentNode()) |
| 158 setDocumentForAnonymous(toDocument(node)); | 158 setDocumentForAnonymous(toDocument(node)); |
| 159 | 159 |
| 160 m_isAllASCII = m_text.containsOnlyASCII(); | 160 m_isAllASCII = m_text.containsOnlyASCII(); |
| 161 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); | 161 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); |
| 162 setIsText(); | 162 setIsText(); |
| 163 | 163 |
| 164 view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length()
); | 164 view()->frameView()->incrementVisuallyNonEmptyCharacterCount(m_text.length()
); |
| 165 } | 165 } |
| 166 | 166 |
| 167 #if ENABLE(ASSERT) | 167 #if ENABLE(ASSERT) |
| 168 | 168 |
| 169 RenderText::~RenderText() | 169 LayoutText::~LayoutText() |
| 170 { | 170 { |
| 171 ASSERT(!m_firstTextBox); | 171 ASSERT(!m_firstTextBox); |
| 172 ASSERT(!m_lastTextBox); | 172 ASSERT(!m_lastTextBox); |
| 173 } | 173 } |
| 174 | 174 |
| 175 #endif | 175 #endif |
| 176 | 176 |
| 177 const char* RenderText::renderName() const | 177 const char* LayoutText::renderName() const |
| 178 { | 178 { |
| 179 // FIXME: Rename to LayoutText |
| 179 return "RenderText"; | 180 return "RenderText"; |
| 180 } | 181 } |
| 181 | 182 |
| 182 bool RenderText::isTextFragment() const | 183 bool LayoutText::isTextFragment() const |
| 183 { | 184 { |
| 184 return false; | 185 return false; |
| 185 } | 186 } |
| 186 | 187 |
| 187 bool RenderText::isWordBreak() const | 188 bool LayoutText::isWordBreak() const |
| 188 { | 189 { |
| 189 return false; | 190 return false; |
| 190 } | 191 } |
| 191 | 192 |
| 192 void RenderText::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyl
e) | 193 void LayoutText::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyl
e) |
| 193 { | 194 { |
| 194 // There is no need to ever schedule paint invalidations from a style change
of a text run, since | 195 // There is no need to ever schedule paint invalidations from a style change
of a text run, since |
| 195 // we already did this for the parent of the text run. | 196 // we already did this for the parent of the text run. |
| 196 // We do have to schedule layouts, though, since a style change can force us
to | 197 // We do have to schedule layouts, though, since a style change can force us
to |
| 197 // need to relayout. | 198 // need to relayout. |
| 198 if (diff.needsFullLayout()) { | 199 if (diff.needsFullLayout()) { |
| 199 setNeedsLayoutAndPrefWidthsRecalc(); | 200 setNeedsLayoutAndPrefWidthsRecalc(); |
| 200 m_knownToHaveNoOverflowAndNoFallbackFonts = false; | 201 m_knownToHaveNoOverflowAndNoFallbackFonts = false; |
| 201 } | 202 } |
| 202 | 203 |
| 203 const LayoutStyle& newStyle = styleRef(); | 204 const LayoutStyle& newStyle = styleRef(); |
| 204 ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE; | 205 ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE; |
| 205 ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE; | 206 ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE; |
| 206 if (oldTransform != newStyle.textTransform() || oldSecurity != newStyle.text
Security()) | 207 if (oldTransform != newStyle.textTransform() || oldSecurity != newStyle.text
Security()) |
| 207 transformText(); | 208 transformText(); |
| 208 | 209 |
| 209 // This is an optimization that kicks off font load before layout. | 210 // This is an optimization that kicks off font load before layout. |
| 210 // In order to make it fast, we only check if the first character of the | 211 // In order to make it fast, we only check if the first character of the |
| 211 // text is included in the unicode ranges of the fonts. | 212 // text is included in the unicode ranges of the fonts. |
| 212 if (!text().containsOnlyWhitespace()) | 213 if (!text().containsOnlyWhitespace()) |
| 213 newStyle.font().willUseFontData(text().characterStartingAt(0)); | 214 newStyle.font().willUseFontData(text().characterStartingAt(0)); |
| 214 } | 215 } |
| 215 | 216 |
| 216 void RenderText::removeAndDestroyTextBoxes() | 217 void LayoutText::removeAndDestroyTextBoxes() |
| 217 { | 218 { |
| 218 if (!documentBeingDestroyed()) { | 219 if (!documentBeingDestroyed()) { |
| 219 if (firstTextBox()) { | 220 if (firstTextBox()) { |
| 220 if (isBR()) { | 221 if (isBR()) { |
| 221 RootInlineBox* next = firstTextBox()->root().nextRootBox(); | 222 RootInlineBox* next = firstTextBox()->root().nextRootBox(); |
| 222 if (next) | 223 if (next) |
| 223 next->markDirty(); | 224 next->markDirty(); |
| 224 } | 225 } |
| 225 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) | 226 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) |
| 226 box->remove(); | 227 box->remove(); |
| 227 } else if (parent()) | 228 } else if (parent()) { |
| 228 parent()->dirtyLinesFromChangedChild(this); | 229 parent()->dirtyLinesFromChangedChild(this); |
| 230 } |
| 229 } | 231 } |
| 230 deleteTextBoxes(); | 232 deleteTextBoxes(); |
| 231 } | 233 } |
| 232 | 234 |
| 233 void RenderText::willBeDestroyed() | 235 void LayoutText::willBeDestroyed() |
| 234 { | 236 { |
| 235 if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers
->take(this) : 0) | 237 if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers
->take(this) : 0) |
| 236 delete secureTextTimer; | 238 delete secureTextTimer; |
| 237 | 239 |
| 238 removeAndDestroyTextBoxes(); | 240 removeAndDestroyTextBoxes(); |
| 239 LayoutObject::willBeDestroyed(); | 241 LayoutObject::willBeDestroyed(); |
| 240 } | 242 } |
| 241 | 243 |
| 242 void RenderText::extractTextBox(InlineTextBox* box) | 244 void LayoutText::extractTextBox(InlineTextBox* box) |
| 243 { | 245 { |
| 244 checkConsistency(); | 246 checkConsistency(); |
| 245 | 247 |
| 246 m_lastTextBox = box->prevTextBox(); | 248 m_lastTextBox = box->prevTextBox(); |
| 247 if (box == m_firstTextBox) | 249 if (box == m_firstTextBox) |
| 248 m_firstTextBox = 0; | 250 m_firstTextBox = 0; |
| 249 if (box->prevTextBox()) | 251 if (box->prevTextBox()) |
| 250 box->prevTextBox()->setNextTextBox(0); | 252 box->prevTextBox()->setNextTextBox(0); |
| 251 box->setPreviousTextBox(0); | 253 box->setPreviousTextBox(0); |
| 252 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) | 254 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) |
| 253 curr->setExtracted(); | 255 curr->setExtracted(); |
| 254 | 256 |
| 255 checkConsistency(); | 257 checkConsistency(); |
| 256 } | 258 } |
| 257 | 259 |
| 258 void RenderText::attachTextBox(InlineTextBox* box) | 260 void LayoutText::attachTextBox(InlineTextBox* box) |
| 259 { | 261 { |
| 260 checkConsistency(); | 262 checkConsistency(); |
| 261 | 263 |
| 262 if (m_lastTextBox) { | 264 if (m_lastTextBox) { |
| 263 m_lastTextBox->setNextTextBox(box); | 265 m_lastTextBox->setNextTextBox(box); |
| 264 box->setPreviousTextBox(m_lastTextBox); | 266 box->setPreviousTextBox(m_lastTextBox); |
| 265 } else | 267 } else { |
| 266 m_firstTextBox = box; | 268 m_firstTextBox = box; |
| 269 } |
| 267 InlineTextBox* last = box; | 270 InlineTextBox* last = box; |
| 268 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) { | 271 for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) { |
| 269 curr->setExtracted(false); | 272 curr->setExtracted(false); |
| 270 last = curr; | 273 last = curr; |
| 271 } | 274 } |
| 272 m_lastTextBox = last; | 275 m_lastTextBox = last; |
| 273 | 276 |
| 274 checkConsistency(); | 277 checkConsistency(); |
| 275 } | 278 } |
| 276 | 279 |
| 277 void RenderText::removeTextBox(InlineTextBox* box) | 280 void LayoutText::removeTextBox(InlineTextBox* box) |
| 278 { | 281 { |
| 279 checkConsistency(); | 282 checkConsistency(); |
| 280 | 283 |
| 281 if (box == m_firstTextBox) | 284 if (box == m_firstTextBox) |
| 282 m_firstTextBox = box->nextTextBox(); | 285 m_firstTextBox = box->nextTextBox(); |
| 283 if (box == m_lastTextBox) | 286 if (box == m_lastTextBox) |
| 284 m_lastTextBox = box->prevTextBox(); | 287 m_lastTextBox = box->prevTextBox(); |
| 285 if (box->nextTextBox()) | 288 if (box->nextTextBox()) |
| 286 box->nextTextBox()->setPreviousTextBox(box->prevTextBox()); | 289 box->nextTextBox()->setPreviousTextBox(box->prevTextBox()); |
| 287 if (box->prevTextBox()) | 290 if (box->prevTextBox()) |
| 288 box->prevTextBox()->setNextTextBox(box->nextTextBox()); | 291 box->prevTextBox()->setNextTextBox(box->nextTextBox()); |
| 289 | 292 |
| 290 checkConsistency(); | 293 checkConsistency(); |
| 291 } | 294 } |
| 292 | 295 |
| 293 void RenderText::deleteTextBoxes() | 296 void LayoutText::deleteTextBoxes() |
| 294 { | 297 { |
| 295 if (firstTextBox()) { | 298 if (firstTextBox()) { |
| 296 InlineTextBox* next; | 299 InlineTextBox* next; |
| 297 for (InlineTextBox* curr = firstTextBox(); curr; curr = next) { | 300 for (InlineTextBox* curr = firstTextBox(); curr; curr = next) { |
| 298 next = curr->nextTextBox(); | 301 next = curr->nextTextBox(); |
| 299 curr->destroy(); | 302 curr->destroy(); |
| 300 } | 303 } |
| 301 m_firstTextBox = m_lastTextBox = 0; | 304 m_firstTextBox = m_lastTextBox = 0; |
| 302 } | 305 } |
| 303 } | 306 } |
| 304 | 307 |
| 305 PassRefPtr<StringImpl> RenderText::originalText() const | 308 PassRefPtr<StringImpl> LayoutText::originalText() const |
| 306 { | 309 { |
| 307 Node* e = node(); | 310 Node* e = node(); |
| 308 return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0; | 311 return (e && e->isTextNode()) ? toText(e)->dataImpl() : 0; |
| 309 } | 312 } |
| 310 | 313 |
| 311 String RenderText::plainText() const | 314 String LayoutText::plainText() const |
| 312 { | 315 { |
| 313 if (node()) | 316 if (node()) |
| 314 return blink::plainText(rangeOfContents(node()).get()); | 317 return blink::plainText(rangeOfContents(node()).get()); |
| 315 | 318 |
| 316 // FIXME: this is just a stopgap until TextIterator is adapted to support ge
nerated text. | 319 // FIXME: this is just a stopgap until TextIterator is adapted to support ge
nerated text. |
| 317 StringBuilder plainTextBuilder; | 320 StringBuilder plainTextBuilder; |
| 318 for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->ne
xtTextBox()) { | 321 for (InlineTextBox* textBox = firstTextBox(); textBox; textBox = textBox->ne
xtTextBox()) { |
| 319 String text = m_text.substring(textBox->start(), textBox->len()).simplif
yWhiteSpace(WTF::DoNotStripWhiteSpace); | 322 String text = m_text.substring(textBox->start(), textBox->len()).simplif
yWhiteSpace(WTF::DoNotStripWhiteSpace); |
| 320 plainTextBuilder.append(text); | 323 plainTextBuilder.append(text); |
| 321 if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox-
>end() && text.length() && !text.right(1).containsOnlyWhitespace()) | 324 if (textBox->nextTextBox() && textBox->nextTextBox()->start() > textBox-
>end() && text.length() && !text.right(1).containsOnlyWhitespace()) |
| 322 plainTextBuilder.append(space); | 325 plainTextBuilder.append(space); |
| 323 } | 326 } |
| 324 return plainTextBuilder.toString(); | 327 return plainTextBuilder.toString(); |
| 325 } | 328 } |
| 326 | 329 |
| 327 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumu
latedOffset) const | 330 void LayoutText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumu
latedOffset) const |
| 328 { | 331 { |
| 329 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) | 332 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) |
| 330 rects.append(enclosingIntRect(FloatRect(FloatPoint(accumulatedOffset) +
box->topLeft().toFloatPoint(), box->size().toFloatSize()))); | 333 rects.append(enclosingIntRect(FloatRect(FloatPoint(accumulatedOffset) +
box->topLeft().toFloatPoint(), box->size().toFloatSize()))); |
| 331 } | 334 } |
| 332 | 335 |
| 333 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigne
d end, bool useSelectionHeight) | 336 static FloatRect localQuadForTextBox(InlineTextBox* box, unsigned start, unsigne
d end, bool useSelectionHeight) |
| 334 { | 337 { |
| 335 unsigned realEnd = std::min(box->end() + 1, end); | 338 unsigned realEnd = std::min(box->end() + 1, end); |
| 336 LayoutRect r = box->localSelectionRect(start, realEnd); | 339 LayoutRect r = box->localSelectionRect(start, realEnd); |
| 337 if (r.height()) { | 340 if (r.height()) { |
| 338 if (!useSelectionHeight) { | 341 if (!useSelectionHeight) { |
| 339 // Change the height and y position (or width and x for vertical tex
t) | 342 // Change the height and y position (or width and x for vertical tex
t) |
| 340 // because selectionRect uses selection-specific values. | 343 // because selectionRect uses selection-specific values. |
| 341 if (box->isHorizontal()) { | 344 if (box->isHorizontal()) { |
| 342 r.setHeight(box->height()); | 345 r.setHeight(box->height()); |
| 343 r.setY(box->y()); | 346 r.setY(box->y()); |
| 344 } else { | 347 } else { |
| 345 r.setWidth(box->width()); | 348 r.setWidth(box->width()); |
| 346 r.setX(box->x()); | 349 r.setX(box->x()); |
| 347 } | 350 } |
| 348 } | 351 } |
| 349 return FloatRect(r); | 352 return FloatRect(r); |
| 350 } | 353 } |
| 351 return FloatRect(); | 354 return FloatRect(); |
| 352 } | 355 } |
| 353 | 356 |
| 354 void RenderText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u
nsigned end, bool useSelectionHeight, bool* wasFixed) | 357 void LayoutText::absoluteRectsForRange(Vector<IntRect>& rects, unsigned start, u
nsigned end, bool useSelectionHeight, bool* wasFixed) |
| 355 { | 358 { |
| 356 // Work around signed/unsigned issues. This function takes unsigneds, and is
often passed UINT_MAX | 359 // Work around signed/unsigned issues. This function takes unsigneds, and is
often passed UINT_MAX |
| 357 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds
, so changing this | 360 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds
, so changing this |
| 358 // function to take ints causes various internal mismatches. But selectionRe
ct takes ints, and | 361 // function to take ints causes various internal mismatches. But selectionRe
ct takes ints, and |
| 359 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect
to take unsigneds, but | 362 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect
to take unsigneds, but |
| 360 // that would cause many ripple effects, so for now we'll just clamp our uns
igned parameters to INT_MAX. | 363 // that would cause many ripple effects, so for now we'll just clamp our uns
igned parameters to INT_MAX. |
| 361 ASSERT(end == UINT_MAX || end <= INT_MAX); | 364 ASSERT(end == UINT_MAX || end <= INT_MAX); |
| 362 ASSERT(start <= INT_MAX); | 365 ASSERT(start <= INT_MAX); |
| 363 start = std::min(start, static_cast<unsigned>(INT_MAX)); | 366 start = std::min(start, static_cast<unsigned>(INT_MAX)); |
| 364 end = std::min(end, static_cast<unsigned>(INT_MAX)); | 367 end = std::min(end, static_cast<unsigned>(INT_MAX)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 // The ellipsis should be considered to be selected if the end of | 407 // The ellipsis should be considered to be selected if the end of |
| 405 // the selection is past the beginning of the truncation and the | 408 // the selection is past the beginning of the truncation and the |
| 406 // beginning of the selection is before or at the beginning of the trunc
ation. | 409 // beginning of the selection is before or at the beginning of the trunc
ation. |
| 407 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= trunca
tion) | 410 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= trunca
tion) |
| 408 return ellipsis->selectionRect(); | 411 return ellipsis->selectionRect(); |
| 409 } | 412 } |
| 410 | 413 |
| 411 return IntRect(); | 414 return IntRect(); |
| 412 } | 415 } |
| 413 | 416 |
| 414 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, Clippin
gOption option) const | 417 void LayoutText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed, Clippin
gOption option) const |
| 415 { | 418 { |
| 416 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { | 419 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { |
| 417 FloatRect boundaries = box->calculateBoundaries().toFloatRect(); | 420 FloatRect boundaries = box->calculateBoundaries().toFloatRect(); |
| 418 | 421 |
| 419 // Shorten the width of this text box if it ends in an ellipsis. | 422 // Shorten the width of this text box if it ends in an ellipsis. |
| 420 // FIXME: ellipsisRectForBox should switch to return FloatRect soon with
the subpixellayout branch. | 423 // FIXME: ellipsisRectForBox should switch to return FloatRect soon with
the subpixellayout branch. |
| 421 IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(b
ox, 0, textLength()) : IntRect(); | 424 IntRect ellipsisRect = (option == ClipToEllipsis) ? ellipsisRectForBox(b
ox, 0, textLength()) : IntRect(); |
| 422 if (!ellipsisRect.isEmpty()) { | 425 if (!ellipsisRect.isEmpty()) { |
| 423 if (style()->isHorizontalWritingMode()) | 426 if (style()->isHorizontalWritingMode()) |
| 424 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x()); | 427 boundaries.setWidth(ellipsisRect.maxX() - boundaries.x()); |
| 425 else | 428 else |
| 426 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y()); | 429 boundaries.setHeight(ellipsisRect.maxY() - boundaries.y()); |
| 427 } | 430 } |
| 428 quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed)); | 431 quads.append(localToAbsoluteQuad(boundaries, 0, wasFixed)); |
| 429 } | 432 } |
| 430 } | 433 } |
| 431 | 434 |
| 432 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const | 435 void LayoutText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const |
| 433 { | 436 { |
| 434 absoluteQuads(quads, wasFixed, NoClipping); | 437 absoluteQuads(quads, wasFixed, NoClipping); |
| 435 } | 438 } |
| 436 | 439 |
| 437 void RenderText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
unsigned end, bool useSelectionHeight, bool* wasFixed) | 440 void LayoutText::absoluteQuadsForRange(Vector<FloatQuad>& quads, unsigned start,
unsigned end, bool useSelectionHeight, bool* wasFixed) |
| 438 { | 441 { |
| 439 // Work around signed/unsigned issues. This function takes unsigneds, and is
often passed UINT_MAX | 442 // Work around signed/unsigned issues. This function takes unsigneds, and is
often passed UINT_MAX |
| 440 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds
, so changing this | 443 // to mean "all the way to the end". InlineTextBox coordinates are unsigneds
, so changing this |
| 441 // function to take ints causes various internal mismatches. But selectionRe
ct takes ints, and | 444 // function to take ints causes various internal mismatches. But selectionRe
ct takes ints, and |
| 442 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect
to take unsigneds, but | 445 // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect
to take unsigneds, but |
| 443 // that would cause many ripple effects, so for now we'll just clamp our uns
igned parameters to INT_MAX. | 446 // that would cause many ripple effects, so for now we'll just clamp our uns
igned parameters to INT_MAX. |
| 444 ASSERT(end == UINT_MAX || end <= INT_MAX); | 447 ASSERT(end == UINT_MAX || end <= INT_MAX); |
| 445 ASSERT(start <= INT_MAX); | 448 ASSERT(start <= INT_MAX); |
| 446 start = std::min(start, static_cast<unsigned>(INT_MAX)); | 449 start = std::min(start, static_cast<unsigned>(INT_MAX)); |
| 447 end = std::min(end, static_cast<unsigned>(INT_MAX)); | 450 end = std::min(end, static_cast<unsigned>(INT_MAX)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 case AlwaysDownstream: | 516 case AlwaysDownstream: |
| 514 affinity = DOWNSTREAM; | 517 affinity = DOWNSTREAM; |
| 515 break; | 518 break; |
| 516 case AlwaysUpstream: | 519 case AlwaysUpstream: |
| 517 affinity = VP_UPSTREAM_IF_POSSIBLE; | 520 affinity = VP_UPSTREAM_IF_POSSIBLE; |
| 518 break; | 521 break; |
| 519 case UpstreamIfPositionIsNotAtStart: | 522 case UpstreamIfPositionIsNotAtStart: |
| 520 affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DO
WNSTREAM; | 523 affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DO
WNSTREAM; |
| 521 break; | 524 break; |
| 522 } | 525 } |
| 523 int textStartOffset = box->renderer().isText() ? toRenderText(box->renderer(
)).textStartOffset() : 0; | 526 int textStartOffset = box->renderer().isText() ? toLayoutText(box->renderer(
)).textStartOffset() : 0; |
| 524 return box->renderer().createPositionWithAffinity(offset + textStartOffset,
affinity); | 527 return box->renderer().createPositionWithAffinity(offset + textStartOffset,
affinity); |
| 525 } | 528 } |
| 526 | 529 |
| 527 static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset
ForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldA
ffinityBeDownstream) | 530 static PositionWithAffinity createPositionWithAffinityForBoxAfterAdjustingOffset
ForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldA
ffinityBeDownstream) |
| 528 { | 531 { |
| 529 ASSERT(box); | 532 ASSERT(box); |
| 530 ASSERT(offset >= 0); | 533 ASSERT(offset >= 0); |
| 531 | 534 |
| 532 if (offset && static_cast<unsigned>(offset) < box->len()) | 535 if (offset && static_cast<unsigned>(offset) < box->len()) |
| 533 return createPositionWithAffinityForBox(box, box->start() + offset, shou
ldAffinityBeDownstream); | 536 return createPositionWithAffinityForBox(box, box->start() + offset, shou
ldAffinityBeDownstream); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 leftmostBox = prevBox; | 593 leftmostBox = prevBox; |
| 591 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak(); | 594 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak(); |
| 592 } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel()); | 595 } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel()); |
| 593 return createPositionWithAffinityForBox(leftmostBox, | 596 return createPositionWithAffinityForBox(leftmostBox, |
| 594 box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : left
mostBox->caretMaxOffset(), shouldAffinityBeDownstream); | 597 box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : left
mostBox->caretMaxOffset(), shouldAffinityBeDownstream); |
| 595 } | 598 } |
| 596 | 599 |
| 597 return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), sho
uldAffinityBeDownstream); | 600 return createPositionWithAffinityForBox(box, box->caretLeftmostOffset(), sho
uldAffinityBeDownstream); |
| 598 } | 601 } |
| 599 | 602 |
| 600 PositionWithAffinity RenderText::positionForPoint(const LayoutPoint& point) | 603 PositionWithAffinity LayoutText::positionForPoint(const LayoutPoint& point) |
| 601 { | 604 { |
| 602 if (!firstTextBox() || textLength() == 0) | 605 if (!firstTextBox() || textLength() == 0) |
| 603 return createPositionWithAffinity(0, DOWNSTREAM); | 606 return createPositionWithAffinity(0, DOWNSTREAM); |
| 604 | 607 |
| 605 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() :
point.y(); | 608 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() :
point.y(); |
| 606 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y()
: point.x(); | 609 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y()
: point.x(); |
| 607 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); | 610 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); |
| 608 | 611 |
| 609 InlineTextBox* lastBox = 0; | 612 InlineTextBox* lastBox = 0; |
| 610 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { | 613 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 628 } | 631 } |
| 629 | 632 |
| 630 if (lastBox) { | 633 if (lastBox) { |
| 631 ShouldAffinityBeDownstream shouldAffinityBeDownstream; | 634 ShouldAffinityBeDownstream shouldAffinityBeDownstream; |
| 632 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityB
eDownstream); | 635 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityB
eDownstream); |
| 633 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastB
ox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(),
shouldAffinityBeDownstream); | 636 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastB
ox, lastBox->offsetForPosition(pointLineDirection.toFloat()) + lastBox->start(),
shouldAffinityBeDownstream); |
| 634 } | 637 } |
| 635 return createPositionWithAffinity(0, DOWNSTREAM); | 638 return createPositionWithAffinity(0, DOWNSTREAM); |
| 636 } | 639 } |
| 637 | 640 |
| 638 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
outUnit* extraWidthToEndOfLine) | 641 LayoutRect LayoutText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
outUnit* extraWidthToEndOfLine) |
| 639 { | 642 { |
| 640 if (!inlineBox) | 643 if (!inlineBox) |
| 641 return LayoutRect(); | 644 return LayoutRect(); |
| 642 | 645 |
| 643 ASSERT(inlineBox->isInlineTextBox()); | 646 ASSERT(inlineBox->isInlineTextBox()); |
| 644 if (!inlineBox->isInlineTextBox()) | 647 if (!inlineBox->isInlineTextBox()) |
| 645 return LayoutRect(); | 648 return LayoutRect(); |
| 646 | 649 |
| 647 InlineTextBox* box = toInlineTextBox(inlineBox); | 650 InlineTextBox* box = toInlineTextBox(inlineBox); |
| 648 | 651 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 left = std::max(left, leftEdge); | 708 left = std::max(left, leftEdge); |
| 706 left = std::min(left, rootRight - caretWidth); | 709 left = std::min(left, rootRight - caretWidth); |
| 707 } else { | 710 } else { |
| 708 left = std::min(left, rightEdge - caretWidthRightOfOffset); | 711 left = std::min(left, rightEdge - caretWidthRightOfOffset); |
| 709 left = std::max(left, rootLeft); | 712 left = std::max(left, rootLeft); |
| 710 } | 713 } |
| 711 | 714 |
| 712 return LayoutRect(style()->isHorizontalWritingMode() ? IntRect(left, top, ca
retWidth, height) : IntRect(top, left, height, caretWidth)); | 715 return LayoutRect(style()->isHorizontalWritingMode() ? IntRect(left, top, ca
retWidth, height) : IntRect(top, left, height, caretWidth)); |
| 713 } | 716 } |
| 714 | 717 |
| 715 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len
, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallb
ackFonts, GlyphOverflow* glyphOverflow) const | 718 ALWAYS_INLINE float LayoutText::widthFromCache(const Font& f, int start, int len
, float xPos, TextDirection textDirection, HashSet<const SimpleFontData*>* fallb
ackFonts, GlyphOverflow* glyphOverflow) const |
| 716 { | 719 { |
| 717 if (style()->hasTextCombine() && isCombineText()) { | 720 if (style()->hasTextCombine() && isCombineText()) { |
| 718 const RenderCombineText* combineText = toRenderCombineText(this); | 721 const LayoutTextCombine* combineText = toLayoutTextCombine(this); |
| 719 if (combineText->isCombined()) | 722 if (combineText->isCombined()) |
| 720 return combineText->combinedTextWidth(f); | 723 return combineText->combinedTextWidth(f); |
| 721 } | 724 } |
| 722 | 725 |
| 723 if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal &
& m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) { | 726 if (f.isFixedPitch() && f.fontDescription().variant() == FontVariantNormal &
& m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) { |
| 724 bool missingGlyph = false; | 727 bool missingGlyph = false; |
| 725 float monospaceCharacterWidth = f.spaceWidth(); | 728 float monospaceCharacterWidth = f.spaceWidth(); |
| 726 float w = 0; | 729 float w = 0; |
| 727 bool isSpace; | 730 bool isSpace; |
| 728 ASSERT(m_text); | 731 ASSERT(m_text); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 741 w += monospaceCharacterWidth; | 744 w += monospaceCharacterWidth; |
| 742 isSpace = true; | 745 isSpace = true; |
| 743 } else if (c == characterTabulation) { | 746 } else if (c == characterTabulation) { |
| 744 if (layoutStyle.collapseWhiteSpace()) { | 747 if (layoutStyle.collapseWhiteSpace()) { |
| 745 w += monospaceCharacterWidth; | 748 w += monospaceCharacterWidth; |
| 746 isSpace = true; | 749 isSpace = true; |
| 747 } else { | 750 } else { |
| 748 w += f.tabWidth(layoutStyle.tabSize(), xPos + w); | 751 w += f.tabWidth(layoutStyle.tabSize(), xPos + w); |
| 749 isSpace = false; | 752 isSpace = false; |
| 750 } | 753 } |
| 751 } else | 754 } else { |
| 752 isSpace = false; | 755 isSpace = false; |
| 756 } |
| 753 } else { | 757 } else { |
| 754 w += monospaceCharacterWidth; | 758 w += monospaceCharacterWidth; |
| 755 isSpace = false; | 759 isSpace = false; |
| 756 } | 760 } |
| 757 if (isSpace && i > start) | 761 if (isSpace && i > start) |
| 758 w += f.fontDescription().wordSpacing(); | 762 w += f.fontDescription().wordSpacing(); |
| 759 } | 763 } |
| 760 if (!missingGlyph) | 764 if (!missingGlyph) |
| 761 return w; | 765 return w; |
| 762 } | 766 } |
| 763 | 767 |
| 764 TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, start
, len, styleRef(), textDirection); | 768 TextRun run = constructTextRun(const_cast<LayoutText*>(this), f, this, start
, len, styleRef(), textDirection); |
| 765 run.setCharactersLength(textLength() - start); | 769 run.setCharactersLength(textLength() - start); |
| 766 ASSERT(run.charactersLength() >= run.length()); | 770 ASSERT(run.charactersLength() >= run.length()); |
| 767 run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun:
:ForceComplex); | 771 run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun:
:ForceComplex); |
| 768 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); | 772 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); |
| 769 run.setXPos(xPos); | 773 run.setXPos(xPos); |
| 770 return f.width(run, fallbackFonts, glyphOverflow); | 774 return f.width(run, fallbackFonts, glyphOverflow); |
| 771 } | 775 } |
| 772 | 776 |
| 773 void RenderText::trimmedPrefWidths(FloatWillBeLayoutUnit leadWidth, | 777 void LayoutText::trimmedPrefWidths(FloatWillBeLayoutUnit leadWidth, |
| 774 FloatWillBeLayoutUnit& firstLineMinWidth, bool& hasBreakableStart, | 778 FloatWillBeLayoutUnit& firstLineMinWidth, bool& hasBreakableStart, |
| 775 FloatWillBeLayoutUnit& lastLineMinWidth, bool& hasBreakableEnd, | 779 FloatWillBeLayoutUnit& lastLineMinWidth, bool& hasBreakableEnd, |
| 776 bool& hasBreakableChar, bool& hasBreak, | 780 bool& hasBreakableChar, bool& hasBreak, |
| 777 FloatWillBeLayoutUnit& firstLineMaxWidth, FloatWillBeLayoutUnit& lastLineMax
Width, | 781 FloatWillBeLayoutUnit& firstLineMaxWidth, FloatWillBeLayoutUnit& lastLineMax
Width, |
| 778 FloatWillBeLayoutUnit& minWidth, FloatWillBeLayoutUnit& maxWidth, bool& stri
pFrontSpaces, | 782 FloatWillBeLayoutUnit& minWidth, FloatWillBeLayoutUnit& maxWidth, bool& stri
pFrontSpaces, |
| 779 TextDirection direction) | 783 TextDirection direction) |
| 780 { | 784 { |
| 781 bool collapseWhiteSpace = style()->collapseWhiteSpace(); | 785 bool collapseWhiteSpace = style()->collapseWhiteSpace(); |
| 782 if (!collapseWhiteSpace) | 786 if (!collapseWhiteSpace) |
| 783 stripFrontSpaces = false; | 787 stripFrontSpaces = false; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 | 861 |
| 858 if (i == len - 1) { | 862 if (i == len - 1) { |
| 859 // A <pre> run that ends with a newline, as in, e.g., | 863 // A <pre> run that ends with a newline, as in, e.g., |
| 860 // <pre>Some text\n\n<span>More text</pre> | 864 // <pre>Some text\n\n<span>More text</pre> |
| 861 lastLineMaxWidth = FloatWillBeLayoutUnit(); | 865 lastLineMaxWidth = FloatWillBeLayoutUnit(); |
| 862 } | 866 } |
| 863 } | 867 } |
| 864 } | 868 } |
| 865 } | 869 } |
| 866 | 870 |
| 867 float RenderText::minLogicalWidth() const | 871 float LayoutText::minLogicalWidth() const |
| 868 { | 872 { |
| 869 if (preferredLogicalWidthsDirty()) | 873 if (preferredLogicalWidthsDirty()) |
| 870 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0); | 874 const_cast<LayoutText*>(this)->computePreferredLogicalWidths(0); |
| 871 | 875 |
| 872 return m_minWidth; | 876 return m_minWidth; |
| 873 } | 877 } |
| 874 | 878 |
| 875 float RenderText::maxLogicalWidth() const | 879 float LayoutText::maxLogicalWidth() const |
| 876 { | 880 { |
| 877 if (preferredLogicalWidthsDirty()) | 881 if (preferredLogicalWidthsDirty()) |
| 878 const_cast<RenderText*>(this)->computePreferredLogicalWidths(0); | 882 const_cast<LayoutText*>(this)->computePreferredLogicalWidths(0); |
| 879 | 883 |
| 880 return m_maxWidth; | 884 return m_maxWidth; |
| 881 } | 885 } |
| 882 | 886 |
| 883 void RenderText::computePreferredLogicalWidths(float leadWidth) | 887 void LayoutText::computePreferredLogicalWidths(float leadWidth) |
| 884 { | 888 { |
| 885 HashSet<const SimpleFontData*> fallbackFonts; | 889 HashSet<const SimpleFontData*> fallbackFonts; |
| 886 GlyphOverflow glyphOverflow; | 890 GlyphOverflow glyphOverflow; |
| 887 computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow); | 891 computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow); |
| 888 | 892 |
| 889 // We shouldn't change our mind once we "know". | 893 // We shouldn't change our mind once we "know". |
| 890 ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty(
) && glyphOverflow.isZero())); | 894 ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty(
) && glyphOverflow.isZero())); |
| 891 m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyph
Overflow.isZero(); | 895 m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyph
Overflow.isZero(); |
| 892 } | 896 } |
| 893 | 897 |
| 894 static inline float hyphenWidth(RenderText* renderer, const Font& font, TextDire
ction direction) | 898 static inline float hyphenWidth(LayoutText* renderer, const Font& font, TextDire
ction direction) |
| 895 { | 899 { |
| 896 const LayoutStyle& style = renderer->styleRef(); | 900 const LayoutStyle& style = renderer->styleRef(); |
| 897 return font.width(constructTextRun(renderer, font, style.hyphenString().stri
ng(), style, direction)); | 901 return font.width(constructTextRun(renderer, font, style.hyphenString().stri
ng(), style, direction)); |
| 898 } | 902 } |
| 899 | 903 |
| 900 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
mpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) | 904 void LayoutText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
mpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) |
| 901 { | 905 { |
| 902 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflow
AndNoFallbackFonts); | 906 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflow
AndNoFallbackFonts); |
| 903 | 907 |
| 904 m_minWidth = 0; | 908 m_minWidth = 0; |
| 905 m_maxWidth = 0; | 909 m_maxWidth = 0; |
| 906 m_firstLineMinWidth = 0; | 910 m_firstLineMinWidth = 0; |
| 907 m_lastLineLineMinWidth = 0; | 911 m_lastLineLineMinWidth = 0; |
| 908 | 912 |
| 909 if (isBR()) | 913 if (isBR()) |
| 910 return; | 914 return; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 textDirection = run->direction(); | 972 textDirection = run->direction(); |
| 969 } | 973 } |
| 970 | 974 |
| 971 bool previousCharacterIsSpace = isSpace; | 975 bool previousCharacterIsSpace = isSpace; |
| 972 bool isNewline = false; | 976 bool isNewline = false; |
| 973 if (c == newlineCharacter) { | 977 if (c == newlineCharacter) { |
| 974 if (styleToUse.preserveNewline()) { | 978 if (styleToUse.preserveNewline()) { |
| 975 m_hasBreak = true; | 979 m_hasBreak = true; |
| 976 isNewline = true; | 980 isNewline = true; |
| 977 isSpace = false; | 981 isSpace = false; |
| 978 } else | 982 } else { |
| 979 isSpace = true; | 983 isSpace = true; |
| 984 } |
| 980 } else if (c == characterTabulation) { | 985 } else if (c == characterTabulation) { |
| 981 if (!styleToUse.collapseWhiteSpace()) { | 986 if (!styleToUse.collapseWhiteSpace()) { |
| 982 m_hasTab = true; | 987 m_hasTab = true; |
| 983 isSpace = false; | 988 isSpace = false; |
| 984 } else | 989 } else { |
| 985 isSpace = true; | 990 isSpace = true; |
| 991 } |
| 986 } else { | 992 } else { |
| 987 isSpace = c == space; | 993 isSpace = c == space; |
| 988 } | 994 } |
| 989 | 995 |
| 990 bool isBreakableLocation = isNewline || (isSpace && styleToUse.autoWrap(
)); | 996 bool isBreakableLocation = isNewline || (isSpace && styleToUse.autoWrap(
)); |
| 991 if (!i) | 997 if (!i) |
| 992 m_hasBreakableStart = isBreakableLocation; | 998 m_hasBreakableStart = isBreakableLocation; |
| 993 if (i == len - 1) { | 999 if (i == len - 1) { |
| 994 m_hasBreakableEnd = isBreakableLocation; | 1000 m_hasBreakableEnd = isBreakableLocation; |
| 995 m_hasEndWhiteSpace = isNewline || isSpace; | 1001 m_hasEndWhiteSpace = isNewline || isSpace; |
| 996 } | 1002 } |
| 997 | 1003 |
| 998 if (!ignoringSpaces && styleToUse.collapseWhiteSpace() && previousCharac
terIsSpace && isSpace) | 1004 if (!ignoringSpaces && styleToUse.collapseWhiteSpace() && previousCharac
terIsSpace && isSpace) |
| 999 ignoringSpaces = true; | 1005 ignoringSpaces = true; |
| 1000 | 1006 |
| 1001 if (ignoringSpaces && !isSpace) | 1007 if (ignoringSpaces && !isSpace) |
| 1002 ignoringSpaces = false; | 1008 ignoringSpaces = false; |
| 1003 | 1009 |
| 1004 // Ignore spaces and soft hyphens | 1010 // Ignore spaces and soft hyphens |
| 1005 if (ignoringSpaces) { | 1011 if (ignoringSpaces) { |
| 1006 ASSERT(lastWordBoundary == i); | 1012 ASSERT(lastWordBoundary == i); |
| 1007 lastWordBoundary++; | 1013 lastWordBoundary++; |
| 1008 continue; | 1014 continue; |
| 1009 } else if (c == softHyphen) { | 1015 } |
| 1016 if (c == softHyphen) { |
| 1010 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoun
dary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow); | 1017 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoun
dary, leadWidth + currMaxWidth, textDirection, &fallbackFonts, &glyphOverflow); |
| 1011 if (firstGlyphLeftOverflow < 0) | 1018 if (firstGlyphLeftOverflow < 0) |
| 1012 firstGlyphLeftOverflow = glyphOverflow.left; | 1019 firstGlyphLeftOverflow = glyphOverflow.left; |
| 1013 lastWordBoundary = i + 1; | 1020 lastWordBoundary = i + 1; |
| 1014 continue; | 1021 continue; |
| 1015 } | 1022 } |
| 1016 | 1023 |
| 1017 bool hasBreak = breakIterator.isBreakable(i, nextBreakable, breakAll ? L
ineBreakType::BreakAll : LineBreakType::Normal); | 1024 bool hasBreak = breakIterator.isBreakable(i, nextBreakable, breakAll ? L
ineBreakType::BreakAll : LineBreakType::Normal); |
| 1018 bool betweenWords = true; | 1025 bool betweenWords = true; |
| 1019 int j = i; | 1026 int j = i; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1041 // space, then subtract its width. | 1048 // space, then subtract its width. |
| 1042 float wordTrailingSpaceWidth = 0; | 1049 float wordTrailingSpaceWidth = 0; |
| 1043 if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)
) { | 1050 if (isSpace && (f.fontDescription().typesettingFeatures() & Kerning)
) { |
| 1044 ASSERT(textDirection >=0 && textDirection <= 1); | 1051 ASSERT(textDirection >=0 && textDirection <= 1); |
| 1045 if (!cachedWordTrailingSpaceWidth[textDirection]) | 1052 if (!cachedWordTrailingSpaceWidth[textDirection]) |
| 1046 cachedWordTrailingSpaceWidth[textDirection] = f.width(constr
uctTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing; | 1053 cachedWordTrailingSpaceWidth[textDirection] = f.width(constr
uctTextRun(this, f, &space, 1, styleToUse, textDirection)) + wordSpacing; |
| 1047 wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirect
ion]; | 1054 wordTrailingSpaceWidth = cachedWordTrailingSpaceWidth[textDirect
ion]; |
| 1048 } | 1055 } |
| 1049 | 1056 |
| 1050 float w; | 1057 float w; |
| 1051 if (wordTrailingSpaceWidth && isSpace) | 1058 if (wordTrailingSpaceWidth && isSpace) { |
| 1052 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth,
textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; | 1059 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth,
textDirection, &fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; |
| 1053 else { | 1060 } else { |
| 1054 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, text
Direction, &fallbackFonts, &glyphOverflow); | 1061 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, text
Direction, &fallbackFonts, &glyphOverflow); |
| 1055 if (c == softHyphen) | 1062 if (c == softHyphen) |
| 1056 currMinWidth += hyphenWidth(this, f, textDirection); | 1063 currMinWidth += hyphenWidth(this, f, textDirection); |
| 1057 } | 1064 } |
| 1058 | 1065 |
| 1059 if (firstGlyphLeftOverflow < 0) | 1066 if (firstGlyphLeftOverflow < 0) |
| 1060 firstGlyphLeftOverflow = glyphOverflow.left; | 1067 firstGlyphLeftOverflow = glyphOverflow.left; |
| 1061 currMinWidth += w; | 1068 currMinWidth += w; |
| 1062 if (betweenWords) { | 1069 if (betweenWords) { |
| 1063 if (lastWordBoundary == i) | 1070 if (lastWordBoundary == i) |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 | 1153 |
| 1147 if (styleToUse.whiteSpace() == PRE) { | 1154 if (styleToUse.whiteSpace() == PRE) { |
| 1148 if (firstLine) | 1155 if (firstLine) |
| 1149 m_firstLineMinWidth = m_maxWidth; | 1156 m_firstLineMinWidth = m_maxWidth; |
| 1150 m_lastLineLineMinWidth = currMaxWidth; | 1157 m_lastLineLineMinWidth = currMaxWidth; |
| 1151 } | 1158 } |
| 1152 | 1159 |
| 1153 clearPreferredLogicalWidthsDirty(); | 1160 clearPreferredLogicalWidthsDirty(); |
| 1154 } | 1161 } |
| 1155 | 1162 |
| 1156 bool RenderText::isAllCollapsibleWhitespace() const | 1163 bool LayoutText::isAllCollapsibleWhitespace() const |
| 1157 { | 1164 { |
| 1158 unsigned length = textLength(); | 1165 unsigned length = textLength(); |
| 1159 if (is8Bit()) { | 1166 if (is8Bit()) { |
| 1160 for (unsigned i = 0; i < length; ++i) { | 1167 for (unsigned i = 0; i < length; ++i) { |
| 1161 if (!style()->isCollapsibleWhiteSpace(characters8()[i])) | 1168 if (!style()->isCollapsibleWhiteSpace(characters8()[i])) |
| 1162 return false; | 1169 return false; |
| 1163 } | 1170 } |
| 1164 return true; | 1171 return true; |
| 1165 } | 1172 } |
| 1166 for (unsigned i = 0; i < length; ++i) { | 1173 for (unsigned i = 0; i < length; ++i) { |
| 1167 if (!style()->isCollapsibleWhiteSpace(characters16()[i])) | 1174 if (!style()->isCollapsibleWhiteSpace(characters16()[i])) |
| 1168 return false; | 1175 return false; |
| 1169 } | 1176 } |
| 1170 return true; | 1177 return true; |
| 1171 } | 1178 } |
| 1172 | 1179 |
| 1173 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const | 1180 bool LayoutText::containsOnlyWhitespace(unsigned from, unsigned len) const |
| 1174 { | 1181 { |
| 1175 ASSERT(m_text); | 1182 ASSERT(m_text); |
| 1176 StringImpl& text = *m_text.impl(); | 1183 StringImpl& text = *m_text.impl(); |
| 1177 unsigned currPos; | 1184 unsigned currPos; |
| 1178 for (currPos = from; | 1185 for (currPos = from; |
| 1179 currPos < from + len && (text[currPos] == newlineCharacter || text[currPos]
== space || text[currPos] == characterTabulation); | 1186 currPos < from + len && (text[currPos] == newlineCharacter || text[currPos]
== space || text[currPos] == characterTabulation); |
| 1180 currPos++) { } | 1187 currPos++) { } |
| 1181 return currPos >= (from + len); | 1188 return currPos >= (from + len); |
| 1182 } | 1189 } |
| 1183 | 1190 |
| 1184 FloatPoint RenderText::firstRunOrigin() const | 1191 FloatPoint LayoutText::firstRunOrigin() const |
| 1185 { | 1192 { |
| 1186 return IntPoint(firstRunX(), firstRunY()); | 1193 return IntPoint(firstRunX(), firstRunY()); |
| 1187 } | 1194 } |
| 1188 | 1195 |
| 1189 float RenderText::firstRunX() const | 1196 float LayoutText::firstRunX() const |
| 1190 { | 1197 { |
| 1191 return m_firstTextBox ? m_firstTextBox->x().toFloat() : 0; | 1198 return m_firstTextBox ? m_firstTextBox->x().toFloat() : 0; |
| 1192 } | 1199 } |
| 1193 | 1200 |
| 1194 float RenderText::firstRunY() const | 1201 float LayoutText::firstRunY() const |
| 1195 { | 1202 { |
| 1196 return m_firstTextBox ? m_firstTextBox->y().toFloat() : 0; | 1203 return m_firstTextBox ? m_firstTextBox->y().toFloat() : 0; |
| 1197 } | 1204 } |
| 1198 | 1205 |
| 1199 void RenderText::setSelectionState(SelectionState state) | 1206 void LayoutText::setSelectionState(SelectionState state) |
| 1200 { | 1207 { |
| 1201 LayoutObject::setSelectionState(state); | 1208 LayoutObject::setSelectionState(state); |
| 1202 | 1209 |
| 1203 if (canUpdateSelectionOnRootLineBoxes()) { | 1210 if (canUpdateSelectionOnRootLineBoxes()) { |
| 1204 if (state == SelectionStart || state == SelectionEnd || state == Selecti
onBoth) { | 1211 if (state == SelectionStart || state == SelectionEnd || state == Selecti
onBoth) { |
| 1205 int startPos, endPos; | 1212 int startPos, endPos; |
| 1206 selectionStartEnd(startPos, endPos); | 1213 selectionStartEnd(startPos, endPos); |
| 1207 if (selectionState() == SelectionStart) { | 1214 if (selectionState() == SelectionStart) { |
| 1208 endPos = textLength(); | 1215 endPos = textLength(); |
| 1209 | 1216 |
| 1210 // to handle selection from end of text to end of line | 1217 // to handle selection from end of text to end of line |
| 1211 if (startPos && startPos == endPos) | 1218 if (startPos && startPos == endPos) |
| 1212 startPos = endPos - 1; | 1219 startPos = endPos - 1; |
| 1213 } else if (selectionState() == SelectionEnd) | 1220 } else if (selectionState() == SelectionEnd) { |
| 1214 startPos = 0; | 1221 startPos = 0; |
| 1222 } |
| 1215 | 1223 |
| 1216 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { | 1224 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { |
| 1217 if (box->isSelected(startPos, endPos)) { | 1225 if (box->isSelected(startPos, endPos)) { |
| 1218 box->root().setHasSelectedChildren(true); | 1226 box->root().setHasSelectedChildren(true); |
| 1219 } | 1227 } |
| 1220 } | 1228 } |
| 1221 } else { | 1229 } else { |
| 1222 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { | 1230 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { |
| 1223 box->root().setHasSelectedChildren(state == SelectionInside); | 1231 box->root().setHasSelectedChildren(state == SelectionInside); |
| 1224 } | 1232 } |
| 1225 } | 1233 } |
| 1226 } | 1234 } |
| 1227 | 1235 |
| 1228 // The containing block can be null in case of an orphaned tree. | 1236 // The containing block can be null in case of an orphaned tree. |
| 1229 LayoutBlock* containingBlock = this->containingBlock(); | 1237 LayoutBlock* containingBlock = this->containingBlock(); |
| 1230 if (containingBlock && !containingBlock->isLayoutView()) | 1238 if (containingBlock && !containingBlock->isLayoutView()) |
| 1231 containingBlock->setSelectionState(state); | 1239 containingBlock->setSelectionState(state); |
| 1232 } | 1240 } |
| 1233 | 1241 |
| 1234 void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset,
unsigned len, bool force) | 1242 void LayoutText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset,
unsigned len, bool force) |
| 1235 { | 1243 { |
| 1236 if (!force && equal(m_text.impl(), text.get())) | 1244 if (!force && equal(m_text.impl(), text.get())) |
| 1237 return; | 1245 return; |
| 1238 | 1246 |
| 1239 unsigned oldLen = textLength(); | 1247 unsigned oldLen = textLength(); |
| 1240 unsigned newLen = text->length(); | 1248 unsigned newLen = text->length(); |
| 1241 int delta = newLen - oldLen; | 1249 int delta = newLen - oldLen; |
| 1242 unsigned end = len ? offset + len - 1 : offset; | 1250 unsigned end = len ? offset + len - 1 : offset; |
| 1243 | 1251 |
| 1244 RootInlineBox* firstRootBox = 0; | 1252 RootInlineBox* firstRootBox = 0; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 // If the text node is empty, dirty the line where new text will be inserted
. | 1310 // If the text node is empty, dirty the line where new text will be inserted
. |
| 1303 if (!firstTextBox() && parent()) { | 1311 if (!firstTextBox() && parent()) { |
| 1304 parent()->dirtyLinesFromChangedChild(this); | 1312 parent()->dirtyLinesFromChangedChild(this); |
| 1305 dirtiedLines = true; | 1313 dirtiedLines = true; |
| 1306 } | 1314 } |
| 1307 | 1315 |
| 1308 m_linesDirty = dirtiedLines; | 1316 m_linesDirty = dirtiedLines; |
| 1309 setText(text, force || dirtiedLines); | 1317 setText(text, force || dirtiedLines); |
| 1310 } | 1318 } |
| 1311 | 1319 |
| 1312 void RenderText::transformText() | 1320 void LayoutText::transformText() |
| 1313 { | 1321 { |
| 1314 if (RefPtr<StringImpl> textToTransform = originalText()) | 1322 if (RefPtr<StringImpl> textToTransform = originalText()) |
| 1315 setText(textToTransform.release(), true); | 1323 setText(textToTransform.release(), true); |
| 1316 } | 1324 } |
| 1317 | 1325 |
| 1318 static inline bool isInlineFlowOrEmptyText(const LayoutObject* o) | 1326 static inline bool isInlineFlowOrEmptyText(const LayoutObject* o) |
| 1319 { | 1327 { |
| 1320 if (o->isLayoutInline()) | 1328 if (o->isLayoutInline()) |
| 1321 return true; | 1329 return true; |
| 1322 if (!o->isText()) | 1330 if (!o->isText()) |
| 1323 return false; | 1331 return false; |
| 1324 return toRenderText(o)->text().isEmpty(); | 1332 return toLayoutText(o)->text().isEmpty(); |
| 1325 } | 1333 } |
| 1326 | 1334 |
| 1327 UChar RenderText::previousCharacter() const | 1335 UChar LayoutText::previousCharacter() const |
| 1328 { | 1336 { |
| 1329 // find previous text renderer if one exists | 1337 // find previous text renderer if one exists |
| 1330 const LayoutObject* previousText = previousInPreOrder(); | 1338 const LayoutObject* previousText = previousInPreOrder(); |
| 1331 for (; previousText; previousText = previousText->previousInPreOrder()) | 1339 for (; previousText; previousText = previousText->previousInPreOrder()) { |
| 1332 if (!isInlineFlowOrEmptyText(previousText)) | 1340 if (!isInlineFlowOrEmptyText(previousText)) |
| 1333 break; | 1341 break; |
| 1342 } |
| 1334 UChar prev = space; | 1343 UChar prev = space; |
| 1335 if (previousText && previousText->isText()) | 1344 if (previousText && previousText->isText()) { |
| 1336 if (StringImpl* previousString = toRenderText(previousText)->text().impl
()) | 1345 if (StringImpl* previousString = toLayoutText(previousText)->text().impl
()) |
| 1337 prev = (*previousString)[previousString->length() - 1]; | 1346 prev = (*previousString)[previousString->length() - 1]; |
| 1347 } |
| 1338 return prev; | 1348 return prev; |
| 1339 } | 1349 } |
| 1340 | 1350 |
| 1341 void RenderText::addLayerHitTestRects(LayerHitTestRects&, const Layer* currentLa
yer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const | 1351 void LayoutText::addLayerHitTestRects(LayerHitTestRects&, const Layer* currentLa
yer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const |
| 1342 { | 1352 { |
| 1343 // Text nodes aren't event targets, so don't descend any further. | 1353 // Text nodes aren't event targets, so don't descend any further. |
| 1344 } | 1354 } |
| 1345 | 1355 |
| 1346 void applyTextTransform(const LayoutStyle* style, String& text, UChar previousCh
aracter) | 1356 void applyTextTransform(const LayoutStyle* style, String& text, UChar previousCh
aracter) |
| 1347 { | 1357 { |
| 1348 if (!style) | 1358 if (!style) |
| 1349 return; | 1359 return; |
| 1350 | 1360 |
| 1351 switch (style->textTransform()) { | 1361 switch (style->textTransform()) { |
| 1352 case TTNONE: | 1362 case TTNONE: |
| 1353 break; | 1363 break; |
| 1354 case CAPITALIZE: | 1364 case CAPITALIZE: |
| 1355 makeCapitalized(&text, previousCharacter); | 1365 makeCapitalized(&text, previousCharacter); |
| 1356 break; | 1366 break; |
| 1357 case UPPERCASE: | 1367 case UPPERCASE: |
| 1358 text = text.upper(style->locale()); | 1368 text = text.upper(style->locale()); |
| 1359 break; | 1369 break; |
| 1360 case LOWERCASE: | 1370 case LOWERCASE: |
| 1361 text = text.lower(style->locale()); | 1371 text = text.lower(style->locale()); |
| 1362 break; | 1372 break; |
| 1363 } | 1373 } |
| 1364 } | 1374 } |
| 1365 | 1375 |
| 1366 void RenderText::setTextInternal(PassRefPtr<StringImpl> text) | 1376 void LayoutText::setTextInternal(PassRefPtr<StringImpl> text) |
| 1367 { | 1377 { |
| 1368 ASSERT(text); | 1378 ASSERT(text); |
| 1369 m_text = text; | 1379 m_text = text; |
| 1370 | 1380 |
| 1371 if (style()) { | 1381 if (style()) { |
| 1372 applyTextTransform(style(), m_text, previousCharacter()); | 1382 applyTextTransform(style(), m_text, previousCharacter()); |
| 1373 | 1383 |
| 1374 // We use the same characters here as for list markers. | 1384 // We use the same characters here as for list markers. |
| 1375 // See the listMarkerText function in LayoutListMarker.cpp. | 1385 // See the listMarkerText function in LayoutListMarker.cpp. |
| 1376 switch (style()->textSecurity()) { | 1386 switch (style()->textSecurity()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1387 } | 1397 } |
| 1388 } | 1398 } |
| 1389 | 1399 |
| 1390 ASSERT(m_text); | 1400 ASSERT(m_text); |
| 1391 ASSERT(!isBR() || (textLength() == 1 && m_text[0] == newlineCharacter)); | 1401 ASSERT(!isBR() || (textLength() == 1 && m_text[0] == newlineCharacter)); |
| 1392 | 1402 |
| 1393 m_isAllASCII = m_text.containsOnlyASCII(); | 1403 m_isAllASCII = m_text.containsOnlyASCII(); |
| 1394 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); | 1404 m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath(); |
| 1395 } | 1405 } |
| 1396 | 1406 |
| 1397 void RenderText::secureText(UChar mask) | 1407 void LayoutText::secureText(UChar mask) |
| 1398 { | 1408 { |
| 1399 if (!m_text.length()) | 1409 if (!m_text.length()) |
| 1400 return; | 1410 return; |
| 1401 | 1411 |
| 1402 int lastTypedCharacterOffsetToReveal = -1; | 1412 int lastTypedCharacterOffsetToReveal = -1; |
| 1403 UChar revealedText; | 1413 UChar revealedText; |
| 1404 SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->ge
t(this) : 0; | 1414 SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->ge
t(this) : 0; |
| 1405 if (secureTextTimer && secureTextTimer->isActive()) { | 1415 if (secureTextTimer && secureTextTimer->isActive()) { |
| 1406 lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOf
fset(); | 1416 lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOf
fset(); |
| 1407 if (lastTypedCharacterOffsetToReveal >= 0) | 1417 if (lastTypedCharacterOffsetToReveal >= 0) |
| 1408 revealedText = m_text[lastTypedCharacterOffsetToReveal]; | 1418 revealedText = m_text[lastTypedCharacterOffsetToReveal]; |
| 1409 } | 1419 } |
| 1410 | 1420 |
| 1411 m_text.fill(mask); | 1421 m_text.fill(mask); |
| 1412 if (lastTypedCharacterOffsetToReveal >= 0) { | 1422 if (lastTypedCharacterOffsetToReveal >= 0) { |
| 1413 m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText
, 1)); | 1423 m_text.replace(lastTypedCharacterOffsetToReveal, 1, String(&revealedText
, 1)); |
| 1414 // m_text may be updated later before timer fires. We invalidate the las
tTypedCharacterOffset to avoid inconsistency. | 1424 // m_text may be updated later before timer fires. We invalidate the las
tTypedCharacterOffset to avoid inconsistency. |
| 1415 secureTextTimer->invalidate(); | 1425 secureTextTimer->invalidate(); |
| 1416 } | 1426 } |
| 1417 } | 1427 } |
| 1418 | 1428 |
| 1419 void RenderText::setText(PassRefPtr<StringImpl> text, bool force) | 1429 void LayoutText::setText(PassRefPtr<StringImpl> text, bool force) |
| 1420 { | 1430 { |
| 1421 ASSERT(text); | 1431 ASSERT(text); |
| 1422 | 1432 |
| 1423 if (!force && equal(m_text.impl(), text.get())) | 1433 if (!force && equal(m_text.impl(), text.get())) |
| 1424 return; | 1434 return; |
| 1425 | 1435 |
| 1426 setTextInternal(text); | 1436 setTextInternal(text); |
| 1427 // If preferredLogicalWidthsDirty() of an orphan child is true, LayoutObject
ChildList:: | 1437 // If preferredLogicalWidthsDirty() of an orphan child is true, LayoutObject
ChildList:: |
| 1428 // insertChildNode() fails to set true to owner. To avoid that, we call | 1438 // insertChildNode() fails to set true to owner. To avoid that, we call |
| 1429 // setNeedsLayoutAndPrefWidthsRecalc() only if this RenderText has parent. | 1439 // setNeedsLayoutAndPrefWidthsRecalc() only if this LayoutText has parent. |
| 1430 if (parent()) | 1440 if (parent()) |
| 1431 setNeedsLayoutAndPrefWidthsRecalc(); | 1441 setNeedsLayoutAndPrefWidthsRecalc(); |
| 1432 m_knownToHaveNoOverflowAndNoFallbackFonts = false; | 1442 m_knownToHaveNoOverflowAndNoFallbackFonts = false; |
| 1433 | 1443 |
| 1434 if (AXObjectCache* cache = document().existingAXObjectCache()) | 1444 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 1435 cache->textChanged(this); | 1445 cache->textChanged(this); |
| 1436 } | 1446 } |
| 1437 | 1447 |
| 1438 void RenderText::dirtyOrDeleteLineBoxesIfNeeded(bool fullLayout) | 1448 void LayoutText::dirtyOrDeleteLineBoxesIfNeeded(bool fullLayout) |
| 1439 { | 1449 { |
| 1440 if (fullLayout) | 1450 if (fullLayout) |
| 1441 deleteTextBoxes(); | 1451 deleteTextBoxes(); |
| 1442 else if (!m_linesDirty) | 1452 else if (!m_linesDirty) |
| 1443 dirtyLineBoxes(); | 1453 dirtyLineBoxes(); |
| 1444 m_linesDirty = false; | 1454 m_linesDirty = false; |
| 1445 } | 1455 } |
| 1446 | 1456 |
| 1447 void RenderText::dirtyLineBoxes() | 1457 void LayoutText::dirtyLineBoxes() |
| 1448 { | 1458 { |
| 1449 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) | 1459 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) |
| 1450 box->dirtyLineBoxes(); | 1460 box->dirtyLineBoxes(); |
| 1451 m_linesDirty = false; | 1461 m_linesDirty = false; |
| 1452 } | 1462 } |
| 1453 | 1463 |
| 1454 InlineTextBox* RenderText::createTextBox(int start, unsigned short length) | 1464 InlineTextBox* LayoutText::createTextBox(int start, unsigned short length) |
| 1455 { | 1465 { |
| 1456 return new InlineTextBox(*this, start, length); | 1466 return new InlineTextBox(*this, start, length); |
| 1457 } | 1467 } |
| 1458 | 1468 |
| 1459 InlineTextBox* RenderText::createInlineTextBox(int start, unsigned short length) | 1469 InlineTextBox* LayoutText::createInlineTextBox(int start, unsigned short length) |
| 1460 { | 1470 { |
| 1461 InlineTextBox* textBox = createTextBox(start, length); | 1471 InlineTextBox* textBox = createTextBox(start, length); |
| 1462 if (!m_firstTextBox) | 1472 if (!m_firstTextBox) { |
| 1463 m_firstTextBox = m_lastTextBox = textBox; | 1473 m_firstTextBox = m_lastTextBox = textBox; |
| 1464 else { | 1474 } else { |
| 1465 m_lastTextBox->setNextTextBox(textBox); | 1475 m_lastTextBox->setNextTextBox(textBox); |
| 1466 textBox->setPreviousTextBox(m_lastTextBox); | 1476 textBox->setPreviousTextBox(m_lastTextBox); |
| 1467 m_lastTextBox = textBox; | 1477 m_lastTextBox = textBox; |
| 1468 } | 1478 } |
| 1469 return textBox; | 1479 return textBox; |
| 1470 } | 1480 } |
| 1471 | 1481 |
| 1472 void RenderText::positionLineBox(InlineBox* box) | 1482 void LayoutText::positionLineBox(InlineBox* box) |
| 1473 { | 1483 { |
| 1474 InlineTextBox* s = toInlineTextBox(box); | 1484 InlineTextBox* s = toInlineTextBox(box); |
| 1475 | 1485 |
| 1476 // FIXME: should not be needed!!! | 1486 // FIXME: should not be needed!!! |
| 1477 if (!s->len()) { | 1487 if (!s->len()) { |
| 1478 // We want the box to be destroyed. | 1488 // We want the box to be destroyed. |
| 1479 s->remove(DontMarkLineBoxes); | 1489 s->remove(DontMarkLineBoxes); |
| 1480 if (m_firstTextBox == s) | 1490 if (m_firstTextBox == s) |
| 1481 m_firstTextBox = s->nextTextBox(); | 1491 m_firstTextBox = s->nextTextBox(); |
| 1482 else | 1492 else |
| 1483 s->prevTextBox()->setNextTextBox(s->nextTextBox()); | 1493 s->prevTextBox()->setNextTextBox(s->nextTextBox()); |
| 1484 if (m_lastTextBox == s) | 1494 if (m_lastTextBox == s) |
| 1485 m_lastTextBox = s->prevTextBox(); | 1495 m_lastTextBox = s->prevTextBox(); |
| 1486 else | 1496 else |
| 1487 s->nextTextBox()->setPreviousTextBox(s->prevTextBox()); | 1497 s->nextTextBox()->setPreviousTextBox(s->prevTextBox()); |
| 1488 s->destroy(); | 1498 s->destroy(); |
| 1489 return; | 1499 return; |
| 1490 } | 1500 } |
| 1491 | 1501 |
| 1492 m_containsReversedText |= !s->isLeftToRightDirection(); | 1502 m_containsReversedText |= !s->isLeftToRightDirection(); |
| 1493 } | 1503 } |
| 1494 | 1504 |
| 1495 float RenderText::width(unsigned from, unsigned len, float xPos, TextDirection t
extDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, Gly
phOverflow* glyphOverflow) const | 1505 float LayoutText::width(unsigned from, unsigned len, float xPos, TextDirection t
extDirection, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, Gly
phOverflow* glyphOverflow) const |
| 1496 { | 1506 { |
| 1497 if (from >= textLength()) | 1507 if (from >= textLength()) |
| 1498 return 0; | 1508 return 0; |
| 1499 | 1509 |
| 1500 if (from + len > textLength()) | 1510 if (from + len > textLength()) |
| 1501 len = textLength() - from; | 1511 len = textLength() - from; |
| 1502 | 1512 |
| 1503 return width(from, len, style(firstLine)->font(), xPos, textDirection, fallb
ackFonts, glyphOverflow); | 1513 return width(from, len, style(firstLine)->font(), xPos, textDirection, fallb
ackFonts, glyphOverflow); |
| 1504 } | 1514 } |
| 1505 | 1515 |
| 1506 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos,
TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, Glyp
hOverflow* glyphOverflow) const | 1516 float LayoutText::width(unsigned from, unsigned len, const Font& f, float xPos,
TextDirection textDirection, HashSet<const SimpleFontData*>* fallbackFonts, Glyp
hOverflow* glyphOverflow) const |
| 1507 { | 1517 { |
| 1508 ASSERT(from + len <= textLength()); | 1518 ASSERT(from + len <= textLength()); |
| 1509 if (!textLength()) | 1519 if (!textLength()) |
| 1510 return 0; | 1520 return 0; |
| 1511 | 1521 |
| 1512 float w; | 1522 float w; |
| 1513 if (&f == &style()->font()) { | 1523 if (&f == &style()->font()) { |
| 1514 if (!style()->preserveNewline() && !from && len == textLength() && (!gly
phOverflow || !glyphOverflow->computeBounds)) { | 1524 if (!style()->preserveNewline() && !from && len == textLength() && (!gly
phOverflow || !glyphOverflow->computeBounds)) { |
| 1515 if (fallbackFonts) { | 1525 if (fallbackFonts) { |
| 1516 ASSERT(glyphOverflow); | 1526 ASSERT(glyphOverflow); |
| 1517 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAnd
NoFallbackFonts) { | 1527 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAnd
NoFallbackFonts) { |
| 1518 const_cast<RenderText*>(this)->computePreferredLogicalWidths
(0, *fallbackFonts, *glyphOverflow); | 1528 const_cast<LayoutText*>(this)->computePreferredLogicalWidths
(0, *fallbackFonts, *glyphOverflow); |
| 1519 // We shouldn't change our mind once we "know". | 1529 // We shouldn't change our mind once we "know". |
| 1520 ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts | 1530 ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts |
| 1521 || (fallbackFonts->isEmpty() && glyphOverflow->isZero())
); | 1531 || (fallbackFonts->isEmpty() && glyphOverflow->isZero())
); |
| 1522 m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts->i
sEmpty() && glyphOverflow->isZero(); | 1532 m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts->i
sEmpty() && glyphOverflow->isZero(); |
| 1523 } | 1533 } |
| 1524 w = m_maxWidth; | 1534 w = m_maxWidth; |
| 1525 } else { | 1535 } else { |
| 1526 w = maxLogicalWidth(); | 1536 w = maxLogicalWidth(); |
| 1527 } | 1537 } |
| 1528 } else { | 1538 } else { |
| 1529 w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts,
glyphOverflow); | 1539 w = widthFromCache(f, from, len, xPos, textDirection, fallbackFonts,
glyphOverflow); |
| 1530 } | 1540 } |
| 1531 } else { | 1541 } else { |
| 1532 TextRun run = constructTextRun(const_cast<RenderText*>(this), f, this, f
rom, len, styleRef(), textDirection); | 1542 TextRun run = constructTextRun(const_cast<LayoutText*>(this), f, this, f
rom, len, styleRef(), textDirection); |
| 1533 run.setCharactersLength(textLength() - from); | 1543 run.setCharactersLength(textLength() - from); |
| 1534 ASSERT(run.charactersLength() >= run.length()); | 1544 ASSERT(run.charactersLength() >= run.length()); |
| 1535 | 1545 |
| 1536 run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : Text
Run::ForceComplex); | 1546 run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : Text
Run::ForceComplex); |
| 1537 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); | 1547 run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); |
| 1538 run.setXPos(xPos); | 1548 run.setXPos(xPos); |
| 1539 w = f.width(run, fallbackFonts, glyphOverflow); | 1549 w = f.width(run, fallbackFonts, glyphOverflow); |
| 1540 } | 1550 } |
| 1541 | 1551 |
| 1542 return w; | 1552 return w; |
| 1543 } | 1553 } |
| 1544 | 1554 |
| 1545 IntRect RenderText::linesBoundingBox() const | 1555 IntRect LayoutText::linesBoundingBox() const |
| 1546 { | 1556 { |
| 1547 IntRect result; | 1557 IntRect result; |
| 1548 | 1558 |
| 1549 ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both
exist. | 1559 ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both e
xist. |
| 1550 if (firstTextBox() && lastTextBox()) { | 1560 if (firstTextBox() && lastTextBox()) { |
| 1551 // Return the width of the minimal left side and the maximal right side. | 1561 // Return the width of the minimal left side and the maximal right side. |
| 1552 float logicalLeftSide = 0; | 1562 float logicalLeftSide = 0; |
| 1553 float logicalRightSide = 0; | 1563 float logicalRightSide = 0; |
| 1554 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBo
x()) { | 1564 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBo
x()) { |
| 1555 if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide) | 1565 if (curr == firstTextBox() || curr->logicalLeft() < logicalLeftSide) |
| 1556 logicalLeftSide = curr->logicalLeft(); | 1566 logicalLeftSide = curr->logicalLeft(); |
| 1557 if (curr == firstTextBox() || curr->logicalRight() > logicalRightSid
e) | 1567 if (curr == firstTextBox() || curr->logicalRight() > logicalRightSid
e) |
| 1558 logicalRightSide = curr->logicalRight(); | 1568 logicalRightSide = curr->logicalRight(); |
| 1559 } | 1569 } |
| 1560 | 1570 |
| 1561 bool isHorizontal = style()->isHorizontalWritingMode(); | 1571 bool isHorizontal = style()->isHorizontalWritingMode(); |
| 1562 | 1572 |
| 1563 float x = isHorizontal ? logicalLeftSide : firstTextBox()->x().toFloat()
; | 1573 float x = isHorizontal ? logicalLeftSide : firstTextBox()->x().toFloat()
; |
| 1564 float y = isHorizontal ? firstTextBox()->y().toFloat() : logicalLeftSide
; | 1574 float y = isHorizontal ? firstTextBox()->y().toFloat() : logicalLeftSide
; |
| 1565 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTe
xtBox()->logicalBottom() - x; | 1575 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastTe
xtBox()->logicalBottom() - x; |
| 1566 float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logic
alRightSide - logicalLeftSide; | 1576 float height = isHorizontal ? lastTextBox()->logicalBottom() - y : logic
alRightSide - logicalLeftSide; |
| 1567 result = enclosingIntRect(FloatRect(x, y, width, height)); | 1577 result = enclosingIntRect(FloatRect(x, y, width, height)); |
| 1568 } | 1578 } |
| 1569 | 1579 |
| 1570 return result; | 1580 return result; |
| 1571 } | 1581 } |
| 1572 | 1582 |
| 1573 LayoutRect RenderText::linesVisualOverflowBoundingBox() const | 1583 LayoutRect LayoutText::linesVisualOverflowBoundingBox() const |
| 1574 { | 1584 { |
| 1575 if (!firstTextBox()) | 1585 if (!firstTextBox()) |
| 1576 return LayoutRect(); | 1586 return LayoutRect(); |
| 1577 | 1587 |
| 1578 // Return the width of the minimal left side and the maximal right side. | 1588 // Return the width of the minimal left side and the maximal right side. |
| 1579 LayoutUnit logicalLeftSide = LayoutUnit::max(); | 1589 LayoutUnit logicalLeftSide = LayoutUnit::max(); |
| 1580 LayoutUnit logicalRightSide = LayoutUnit::min(); | 1590 LayoutUnit logicalRightSide = LayoutUnit::min(); |
| 1581 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox())
{ | 1591 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox())
{ |
| 1582 LayoutRect logicalVisualOverflow = curr->logicalOverflowRect(); | 1592 LayoutRect logicalVisualOverflow = curr->logicalOverflowRect(); |
| 1583 logicalLeftSide = std::min(logicalLeftSide, logicalVisualOverflow.x()); | 1593 logicalLeftSide = std::min(logicalLeftSide, logicalVisualOverflow.x()); |
| 1584 logicalRightSide = std::max(logicalRightSide, logicalVisualOverflow.maxX
()); | 1594 logicalRightSide = std::max(logicalRightSide, logicalVisualOverflow.maxX
()); |
| 1585 } | 1595 } |
| 1586 | 1596 |
| 1587 LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow(); | 1597 LayoutUnit logicalTop = firstTextBox()->logicalTopVisualOverflow(); |
| 1588 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide; | 1598 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide; |
| 1589 LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - lo
gicalTop; | 1599 LayoutUnit logicalHeight = lastTextBox()->logicalBottomVisualOverflow() - lo
gicalTop; |
| 1590 | 1600 |
| 1591 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight); | 1601 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight); |
| 1592 if (!style()->isHorizontalWritingMode()) | 1602 if (!style()->isHorizontalWritingMode()) |
| 1593 rect = rect.transposedRect(); | 1603 rect = rect.transposedRect(); |
| 1594 return rect; | 1604 return rect; |
| 1595 } | 1605 } |
| 1596 | 1606 |
| 1597 LayoutRect RenderText::clippedOverflowRectForPaintInvalidation(const LayoutBoxMo
delObject* paintInvalidationContainer, const PaintInvalidationState* paintInvali
dationState) const | 1607 LayoutRect LayoutText::clippedOverflowRectForPaintInvalidation(const LayoutBoxMo
delObject* paintInvalidationContainer, const PaintInvalidationState* paintInvali
dationState) const |
| 1598 { | 1608 { |
| 1599 if (style()->visibility() != VISIBLE) | 1609 if (style()->visibility() != VISIBLE) |
| 1600 return LayoutRect(); | 1610 return LayoutRect(); |
| 1601 | 1611 |
| 1602 LayoutRect paintInvalidationRect(linesVisualOverflowBoundingBox()); | 1612 LayoutRect paintInvalidationRect(linesVisualOverflowBoundingBox()); |
| 1603 mapRectToPaintInvalidationBacking(paintInvalidationContainer, paintInvalidat
ionRect, paintInvalidationState); | 1613 mapRectToPaintInvalidationBacking(paintInvalidationContainer, paintInvalidat
ionRect, paintInvalidationState); |
| 1604 return paintInvalidationRect; | 1614 return paintInvalidationRect; |
| 1605 } | 1615 } |
| 1606 | 1616 |
| 1607 LayoutRect RenderText::selectionRectForPaintInvalidation(const LayoutBoxModelObj
ect* paintInvalidationContainer) const | 1617 LayoutRect LayoutText::selectionRectForPaintInvalidation(const LayoutBoxModelObj
ect* paintInvalidationContainer) const |
| 1608 { | 1618 { |
| 1609 ASSERT(!needsLayout()); | 1619 ASSERT(!needsLayout()); |
| 1610 | 1620 |
| 1611 if (selectionState() == SelectionNone) | 1621 if (selectionState() == SelectionNone) |
| 1612 return LayoutRect(); | 1622 return LayoutRect(); |
| 1613 LayoutBlock* cb = containingBlock(); | 1623 LayoutBlock* cb = containingBlock(); |
| 1614 if (!cb) | 1624 if (!cb) |
| 1615 return LayoutRect(); | 1625 return LayoutRect(); |
| 1616 | 1626 |
| 1617 // Now calculate startPos and endPos for painting selection. | 1627 // Now calculate startPos and endPos for painting selection. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1639 rect.unite(LayoutRect(ellipsisRectForBox(box, startPos, endPos))); | 1649 rect.unite(LayoutRect(ellipsisRectForBox(box, startPos, endPos))); |
| 1640 } | 1650 } |
| 1641 | 1651 |
| 1642 mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0); | 1652 mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0); |
| 1643 // FIXME: groupedMapping() leaks the squashing abstraction. | 1653 // FIXME: groupedMapping() leaks the squashing abstraction. |
| 1644 if (paintInvalidationContainer->layer()->groupedMapping()) | 1654 if (paintInvalidationContainer->layer()->groupedMapping()) |
| 1645 Layer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect
); | 1655 Layer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect
); |
| 1646 return rect; | 1656 return rect; |
| 1647 } | 1657 } |
| 1648 | 1658 |
| 1649 int RenderText::caretMinOffset() const | 1659 int LayoutText::caretMinOffset() const |
| 1650 { | 1660 { |
| 1651 InlineTextBox* box = firstTextBox(); | 1661 InlineTextBox* box = firstTextBox(); |
| 1652 if (!box) | 1662 if (!box) |
| 1653 return 0; | 1663 return 0; |
| 1654 int minOffset = box->start(); | 1664 int minOffset = box->start(); |
| 1655 for (box = box->nextTextBox(); box; box = box->nextTextBox()) | 1665 for (box = box->nextTextBox(); box; box = box->nextTextBox()) |
| 1656 minOffset = std::min<int>(minOffset, box->start()); | 1666 minOffset = std::min<int>(minOffset, box->start()); |
| 1657 return minOffset; | 1667 return minOffset; |
| 1658 } | 1668 } |
| 1659 | 1669 |
| 1660 int RenderText::caretMaxOffset() const | 1670 int LayoutText::caretMaxOffset() const |
| 1661 { | 1671 { |
| 1662 InlineTextBox* box = lastTextBox(); | 1672 InlineTextBox* box = lastTextBox(); |
| 1663 if (!lastTextBox()) | 1673 if (!lastTextBox()) |
| 1664 return textLength(); | 1674 return textLength(); |
| 1665 | 1675 |
| 1666 int maxOffset = box->start() + box->len(); | 1676 int maxOffset = box->start() + box->len(); |
| 1667 for (box = box->prevTextBox(); box; box = box->prevTextBox()) | 1677 for (box = box->prevTextBox(); box; box = box->prevTextBox()) |
| 1668 maxOffset = std::max<int>(maxOffset, box->start() + box->len()); | 1678 maxOffset = std::max<int>(maxOffset, box->start() + box->len()); |
| 1669 return maxOffset; | 1679 return maxOffset; |
| 1670 } | 1680 } |
| 1671 | 1681 |
| 1672 unsigned RenderText::renderedTextLength() const | 1682 unsigned LayoutText::renderedTextLength() const |
| 1673 { | 1683 { |
| 1674 int l = 0; | 1684 int len = 0; |
| 1675 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) | 1685 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) |
| 1676 l += box->len(); | 1686 len += box->len(); |
| 1677 return l; | 1687 return len; |
| 1678 } | 1688 } |
| 1679 | 1689 |
| 1680 int RenderText::previousOffset(int current) const | 1690 int LayoutText::previousOffset(int current) const |
| 1681 { | 1691 { |
| 1682 if (isAllASCII() || m_text.is8Bit()) | 1692 if (isAllASCII() || m_text.is8Bit()) |
| 1683 return current - 1; | 1693 return current - 1; |
| 1684 | 1694 |
| 1685 StringImpl* textImpl = m_text.impl(); | 1695 StringImpl* textImpl = m_text.impl(); |
| 1686 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(
), textImpl->length()); | 1696 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(
), textImpl->length()); |
| 1687 if (!iterator) | 1697 if (!iterator) |
| 1688 return current - 1; | 1698 return current - 1; |
| 1689 | 1699 |
| 1690 long result = iterator->preceding(current); | 1700 long result = iterator->preceding(current); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1728 } | 1738 } |
| 1729 | 1739 |
| 1730 inline bool isRegionalIndicator(UChar32 c) | 1740 inline bool isRegionalIndicator(UChar32 c) |
| 1731 { | 1741 { |
| 1732 // National flag emoji each consists of a pair of regional indicator symbols
. | 1742 // National flag emoji each consists of a pair of regional indicator symbols
. |
| 1733 return 0x1F1E6 <= c && c <= 0x1F1FF; | 1743 return 0x1F1E6 <= c && c <= 0x1F1FF; |
| 1734 } | 1744 } |
| 1735 | 1745 |
| 1736 #endif | 1746 #endif |
| 1737 | 1747 |
| 1738 int RenderText::previousOffsetForBackwardDeletion(int current) const | 1748 int LayoutText::previousOffsetForBackwardDeletion(int current) const |
| 1739 { | 1749 { |
| 1740 #if OS(POSIX) | 1750 #if OS(POSIX) |
| 1741 ASSERT(m_text); | 1751 ASSERT(m_text); |
| 1742 StringImpl& text = *m_text.impl(); | 1752 StringImpl& text = *m_text.impl(); |
| 1743 UChar32 character; | 1753 UChar32 character; |
| 1744 bool sawRegionalIndicator = false; | 1754 bool sawRegionalIndicator = false; |
| 1745 while (current > 0) { | 1755 while (current > 0) { |
| 1746 if (U16_IS_TRAIL(text[--current])) | 1756 if (U16_IS_TRAIL(text[--current])) |
| 1747 --current; | 1757 --current; |
| 1748 if (current < 0) | 1758 if (current < 0) |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1823 #else | 1833 #else |
| 1824 // Platforms other than Unix-like delete by one code point. | 1834 // Platforms other than Unix-like delete by one code point. |
| 1825 if (U16_IS_TRAIL(m_text[--current])) | 1835 if (U16_IS_TRAIL(m_text[--current])) |
| 1826 --current; | 1836 --current; |
| 1827 if (current < 0) | 1837 if (current < 0) |
| 1828 current = 0; | 1838 current = 0; |
| 1829 return current; | 1839 return current; |
| 1830 #endif | 1840 #endif |
| 1831 } | 1841 } |
| 1832 | 1842 |
| 1833 int RenderText::nextOffset(int current) const | 1843 int LayoutText::nextOffset(int current) const |
| 1834 { | 1844 { |
| 1835 if (isAllASCII() || m_text.is8Bit()) | 1845 if (isAllASCII() || m_text.is8Bit()) |
| 1836 return current + 1; | 1846 return current + 1; |
| 1837 | 1847 |
| 1838 StringImpl* textImpl = m_text.impl(); | 1848 StringImpl* textImpl = m_text.impl(); |
| 1839 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(
), textImpl->length()); | 1849 TextBreakIterator* iterator = cursorMovementIterator(textImpl->characters16(
), textImpl->length()); |
| 1840 if (!iterator) | 1850 if (!iterator) |
| 1841 return current + 1; | 1851 return current + 1; |
| 1842 | 1852 |
| 1843 long result = iterator->following(current); | 1853 long result = iterator->following(current); |
| 1844 if (result == TextBreakDone) | 1854 if (result == TextBreakDone) |
| 1845 result = current + 1; | 1855 result = current + 1; |
| 1846 | 1856 |
| 1847 return result; | 1857 return result; |
| 1848 } | 1858 } |
| 1849 | 1859 |
| 1850 bool RenderText::computeCanUseSimpleFontCodePath() const | 1860 bool LayoutText::computeCanUseSimpleFontCodePath() const |
| 1851 { | 1861 { |
| 1852 if (isAllASCII() || m_text.is8Bit()) | 1862 if (isAllASCII() || m_text.is8Bit()) |
| 1853 return true; | 1863 return true; |
| 1854 return Character::characterRangeCodePath(characters16(), length()) == Simple
Path; | 1864 return Character::characterRangeCodePath(characters16(), length()) == Simple
Path; |
| 1855 } | 1865 } |
| 1856 | 1866 |
| 1857 #if ENABLE(ASSERT) | 1867 #if ENABLE(ASSERT) |
| 1858 | 1868 |
| 1859 void RenderText::checkConsistency() const | 1869 void LayoutText::checkConsistency() const |
| 1860 { | 1870 { |
| 1861 #ifdef CHECK_CONSISTENCY | 1871 #ifdef CHECK_CONSISTENCY |
| 1862 const InlineTextBox* prev = 0; | 1872 const InlineTextBox* prev = 0; |
| 1863 for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child-
>nextTextBox()) { | 1873 for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child-
>nextTextBox()) { |
| 1864 ASSERT(child->renderer() == this); | 1874 ASSERT(child->renderer() == this); |
| 1865 ASSERT(child->prevTextBox() == prev); | 1875 ASSERT(child->prevTextBox() == prev); |
| 1866 prev = child; | 1876 prev = child; |
| 1867 } | 1877 } |
| 1868 ASSERT(prev == m_lastTextBox); | 1878 ASSERT(prev == m_lastTextBox); |
| 1869 #endif | 1879 #endif |
| 1870 } | 1880 } |
| 1871 | 1881 |
| 1872 #endif | 1882 #endif |
| 1873 | 1883 |
| 1874 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacter
Offset) | 1884 void LayoutText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacter
Offset) |
| 1875 { | 1885 { |
| 1876 if (!gSecureTextTimers) | 1886 if (!gSecureTextTimers) |
| 1877 gSecureTextTimers = new SecureTextTimerMap; | 1887 gSecureTextTimers = new SecureTextTimerMap; |
| 1878 | 1888 |
| 1879 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this); | 1889 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this); |
| 1880 if (!secureTextTimer) { | 1890 if (!secureTextTimer) { |
| 1881 secureTextTimer = new SecureTextTimer(this); | 1891 secureTextTimer = new SecureTextTimer(this); |
| 1882 gSecureTextTimers->add(this, secureTextTimer); | 1892 gSecureTextTimers->add(this, secureTextTimer); |
| 1883 } | 1893 } |
| 1884 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); | 1894 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); |
| 1885 } | 1895 } |
| 1886 | 1896 |
| 1887 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox() | 1897 PassRefPtr<AbstractInlineTextBox> LayoutText::firstAbstractInlineTextBox() |
| 1888 { | 1898 { |
| 1889 return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox); | 1899 return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox); |
| 1890 } | 1900 } |
| 1891 | 1901 |
| 1892 void RenderText::invalidateDisplayItemClients(DisplayItemList* displayItemList)
const | 1902 void LayoutText::invalidateDisplayItemClients(DisplayItemList* displayItemList)
const |
| 1893 { | 1903 { |
| 1894 LayoutObject::invalidateDisplayItemClients(displayItemList); | 1904 LayoutObject::invalidateDisplayItemClients(displayItemList); |
| 1895 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) | 1905 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) |
| 1896 displayItemList->invalidate(box->displayItemClient()); | 1906 displayItemList->invalidate(box->displayItemClient()); |
| 1897 } | 1907 } |
| 1898 | 1908 |
| 1899 } // namespace blink | 1909 } // namespace blink |
| OLD | NEW |