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 |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 | 206 |
207 if (!text().containsOnlyWhitespace()) | 207 if (!text().containsOnlyWhitespace()) |
208 newStyle->font().willUseFontData(); | 208 newStyle->font().willUseFontData(); |
209 } | 209 } |
210 | 210 |
211 void RenderText::removeAndDestroyTextBoxes() | 211 void RenderText::removeAndDestroyTextBoxes() |
212 { | 212 { |
213 if (!documentBeingDestroyed()) { | 213 if (!documentBeingDestroyed()) { |
214 if (firstTextBox()) { | 214 if (firstTextBox()) { |
215 if (isBR()) { | 215 if (isBR()) { |
216 RootInlineBox* next = firstTextBox()->root()->nextRootBox(); | 216 RootInlineBox* next = firstTextBox()->root().nextRootBox(); |
217 if (next) | 217 if (next) |
218 next->markDirty(); | 218 next->markDirty(); |
219 } | 219 } |
220 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) | 220 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) |
221 box->remove(); | 221 box->remove(); |
222 } else if (parent()) | 222 } else if (parent()) |
223 parent()->dirtyLinesFromChangedChild(this); | 223 parent()->dirtyLinesFromChangedChild(this); |
224 } | 224 } |
225 deleteTextBoxes(); | 225 deleteTextBoxes(); |
226 } | 226 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigne
d endPos) | 385 static IntRect ellipsisRectForBox(InlineTextBox* box, unsigned startPos, unsigne
d endPos) |
386 { | 386 { |
387 if (!box) | 387 if (!box) |
388 return IntRect(); | 388 return IntRect(); |
389 | 389 |
390 unsigned short truncation = box->truncation(); | 390 unsigned short truncation = box->truncation(); |
391 if (truncation == cNoTruncation) | 391 if (truncation == cNoTruncation) |
392 return IntRect(); | 392 return IntRect(); |
393 | 393 |
394 IntRect rect; | 394 IntRect rect; |
395 if (EllipsisBox* ellipsis = box->root()->ellipsisBox()) { | 395 if (EllipsisBox* ellipsis = box->root().ellipsisBox()) { |
396 int ellipsisStartPosition = max<int>(startPos - box->start(), 0); | 396 int ellipsisStartPosition = max<int>(startPos - box->start(), 0); |
397 int ellipsisEndPosition = min<int>(endPos - box->start(), box->len()); | 397 int ellipsisEndPosition = min<int>(endPos - box->start(), box->len()); |
398 | 398 |
399 // The ellipsis should be considered to be selected if the end of | 399 // The ellipsis should be considered to be selected if the end of |
400 // the selection is past the beginning of the truncation and the | 400 // the selection is past the beginning of the truncation and the |
401 // beginning of the selection is before or at the beginning of the trunc
ation. | 401 // beginning of the selection is before or at the beginning of the trunc
ation. |
402 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= trunca
tion) | 402 if (ellipsisEndPosition >= truncation && ellipsisStartPosition <= trunca
tion) |
403 return ellipsis->selectionRect(); | 403 return ellipsis->selectionRect(); |
404 } | 404 } |
405 | 405 |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 | 620 |
621 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() :
point.y(); | 621 LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() :
point.y(); |
622 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y()
: point.x(); | 622 LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y()
: point.x(); |
623 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); | 623 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); |
624 | 624 |
625 InlineTextBox* lastBox = 0; | 625 InlineTextBox* lastBox = 0; |
626 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { | 626 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { |
627 if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild()
&& !box->nextLeafChild()->isLineBreak()) | 627 if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild()
&& !box->nextLeafChild()->isLineBreak()) |
628 box = box->nextTextBox(); | 628 box = box->nextTextBox(); |
629 | 629 |
630 RootInlineBox* rootBox = box->root(); | 630 RootInlineBox& rootBox = box->root(); |
631 LayoutUnit top = min(rootBox->selectionTop(), rootBox->lineTop()); | 631 LayoutUnit top = min(rootBox.selectionTop(), rootBox.lineTop()); |
632 if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirecti
on == top)) { | 632 if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirecti
on == top)) { |
633 LayoutUnit bottom = rootBox->selectionBottom(); | 633 LayoutUnit bottom = rootBox.selectionBottom(); |
634 if (rootBox->nextRootBox()) | 634 if (rootBox.nextRootBox()) |
635 bottom = min(bottom, rootBox->nextRootBox()->lineTop()); | 635 bottom = min(bottom, rootBox.nextRootBox()->lineTop()); |
636 | 636 |
637 if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockD
irection == bottom)) { | 637 if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockD
irection == bottom)) { |
638 ShouldAffinityBeDownstream shouldAffinityBeDownstream; | 638 ShouldAffinityBeDownstream shouldAffinityBeDownstream; |
639 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldA
ffinityBeDownstream)) | 639 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldA
ffinityBeDownstream)) |
640 return createPositionWithAffinityForBoxAfterAdjustingOffsetF
orBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstre
am); | 640 return createPositionWithAffinityForBoxAfterAdjustingOffsetF
orBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstre
am); |
641 } | 641 } |
642 } | 642 } |
643 lastBox = box; | 643 lastBox = box; |
644 } | 644 } |
645 | 645 |
646 if (lastBox) { | 646 if (lastBox) { |
647 ShouldAffinityBeDownstream shouldAffinityBeDownstream; | 647 ShouldAffinityBeDownstream shouldAffinityBeDownstream; |
648 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityB
eDownstream); | 648 lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityB
eDownstream); |
649 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastB
ox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAff
inityBeDownstream); | 649 return createPositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(lastB
ox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAff
inityBeDownstream); |
650 } | 650 } |
651 return createPositionWithAffinity(0, DOWNSTREAM); | 651 return createPositionWithAffinity(0, DOWNSTREAM); |
652 } | 652 } |
653 | 653 |
654 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
outUnit* extraWidthToEndOfLine) | 654 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
outUnit* extraWidthToEndOfLine) |
655 { | 655 { |
656 if (!inlineBox) | 656 if (!inlineBox) |
657 return LayoutRect(); | 657 return LayoutRect(); |
658 | 658 |
659 ASSERT(inlineBox->isInlineTextBox()); | 659 ASSERT(inlineBox->isInlineTextBox()); |
660 if (!inlineBox->isInlineTextBox()) | 660 if (!inlineBox->isInlineTextBox()) |
661 return LayoutRect(); | 661 return LayoutRect(); |
662 | 662 |
663 InlineTextBox* box = toInlineTextBox(inlineBox); | 663 InlineTextBox* box = toInlineTextBox(inlineBox); |
664 | 664 |
665 int height = box->root()->selectionHeight(); | 665 int height = box->root().selectionHeight(); |
666 int top = box->root()->selectionTop(); | 666 int top = box->root().selectionTop(); |
667 | 667 |
668 // Go ahead and round left to snap it to the nearest pixel. | 668 // Go ahead and round left to snap it to the nearest pixel. |
669 float left = box->positionForOffset(caretOffset); | 669 float left = box->positionForOffset(caretOffset); |
670 | 670 |
671 // Distribute the caret's width to either side of the offset. | 671 // Distribute the caret's width to either side of the offset. |
672 int caretWidthLeftOfOffset = caretWidth / 2; | 672 int caretWidthLeftOfOffset = caretWidth / 2; |
673 left -= caretWidthLeftOfOffset; | 673 left -= caretWidthLeftOfOffset; |
674 int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset; | 674 int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset; |
675 | 675 |
676 left = roundf(left); | 676 left = roundf(left); |
677 | 677 |
678 float rootLeft = box->root()->logicalLeft(); | 678 float rootLeft = box->root().logicalLeft(); |
679 float rootRight = box->root()->logicalRight(); | 679 float rootRight = box->root().logicalRight(); |
680 | 680 |
681 // FIXME: should we use the width of the root inline box or the | 681 // FIXME: should we use the width of the root inline box or the |
682 // width of the containing block for this? | 682 // width of the containing block for this? |
683 if (extraWidthToEndOfLine) | 683 if (extraWidthToEndOfLine) |
684 *extraWidthToEndOfLine = (box->root()->logicalWidth() + rootLeft) - (lef
t + 1); | 684 *extraWidthToEndOfLine = (box->root().logicalWidth() + rootLeft) - (left
+ 1); |
685 | 685 |
686 RenderBlock* cb = containingBlock(); | 686 RenderBlock* cb = containingBlock(); |
687 RenderStyle* cbStyle = cb->style(); | 687 RenderStyle* cbStyle = cb->style(); |
688 | 688 |
689 float leftEdge; | 689 float leftEdge; |
690 float rightEdge; | 690 float rightEdge; |
691 leftEdge = min<float>(0, rootLeft); | 691 leftEdge = min<float>(0, rootLeft); |
692 rightEdge = max<float>(cb->logicalWidth(), rootRight); | 692 rightEdge = max<float>(cb->logicalWidth(), rootRight); |
693 | 693 |
694 bool rightAligned = false; | 694 bool rightAligned = false; |
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1184 endPos = textLength(); | 1184 endPos = textLength(); |
1185 | 1185 |
1186 // to handle selection from end of text to end of line | 1186 // to handle selection from end of text to end of line |
1187 if (startPos && startPos == endPos) | 1187 if (startPos && startPos == endPos) |
1188 startPos = endPos - 1; | 1188 startPos = endPos - 1; |
1189 } else if (selectionState() == SelectionEnd) | 1189 } else if (selectionState() == SelectionEnd) |
1190 startPos = 0; | 1190 startPos = 0; |
1191 | 1191 |
1192 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { | 1192 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { |
1193 if (box->isSelected(startPos, endPos)) { | 1193 if (box->isSelected(startPos, endPos)) { |
1194 RootInlineBox* root = box->root(); | 1194 box->root().setHasSelectedChildren(true); |
1195 if (root) | |
1196 root->setHasSelectedChildren(true); | |
1197 } | 1195 } |
1198 } | 1196 } |
1199 } else { | 1197 } else { |
1200 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { | 1198 for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBo
x()) { |
1201 RootInlineBox* root = box->root(); | 1199 box->root().setHasSelectedChildren(state == SelectionInside); |
1202 if (root) | |
1203 root->setHasSelectedChildren(state == SelectionInside); | |
1204 } | 1200 } |
1205 } | 1201 } |
1206 } | 1202 } |
1207 | 1203 |
1208 // The containing block can be null in case of an orphaned tree. | 1204 // The containing block can be null in case of an orphaned tree. |
1209 RenderBlock* containingBlock = this->containingBlock(); | 1205 RenderBlock* containingBlock = this->containingBlock(); |
1210 if (containingBlock && !containingBlock->isRenderView()) | 1206 if (containingBlock && !containingBlock->isRenderView()) |
1211 containingBlock->setSelectionState(state); | 1207 containingBlock->setSelectionState(state); |
1212 } | 1208 } |
1213 | 1209 |
(...skipping 15 matching lines...) Expand all Loading... |
1229 // Dirty all text boxes that include characters in between offset and offset
+len. | 1225 // Dirty all text boxes that include characters in between offset and offset
+len. |
1230 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox())
{ | 1226 for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox())
{ |
1231 // FIXME: This shouldn't rely on the end of a dirty line box. See https:
//bugs.webkit.org/show_bug.cgi?id=97264 | 1227 // FIXME: This shouldn't rely on the end of a dirty line box. See https:
//bugs.webkit.org/show_bug.cgi?id=97264 |
1232 // Text run is entirely before the affected range. | 1228 // Text run is entirely before the affected range. |
1233 if (curr->end() < offset) | 1229 if (curr->end() < offset) |
1234 continue; | 1230 continue; |
1235 | 1231 |
1236 // Text run is entirely after the affected range. | 1232 // Text run is entirely after the affected range. |
1237 if (curr->start() > end) { | 1233 if (curr->start() > end) { |
1238 curr->offsetRun(delta); | 1234 curr->offsetRun(delta); |
1239 RootInlineBox* root = curr->root(); | 1235 RootInlineBox* root = &curr->root(); |
1240 if (!firstRootBox) { | 1236 if (!firstRootBox) { |
1241 firstRootBox = root; | 1237 firstRootBox = root; |
1242 // The affected area was in between two runs. Go ahead and mark
the root box of | 1238 // The affected area was in between two runs. Go ahead and mark
the root box of |
1243 // the run after the affected area as dirty. | 1239 // the run after the affected area as dirty. |
1244 firstRootBox->markDirty(); | 1240 firstRootBox->markDirty(); |
1245 dirtiedLines = true; | 1241 dirtiedLines = true; |
1246 } | 1242 } |
1247 lastRootBox = root; | 1243 lastRootBox = root; |
1248 } else if (curr->end() >= offset && curr->end() <= end) { | 1244 } else if (curr->end() >= offset && curr->end() <= end) { |
1249 // Text run overlaps with the left end of the affected range. | 1245 // Text run overlaps with the left end of the affected range. |
(...skipping 13 matching lines...) Expand all Loading... |
1263 // Now we have to walk all of the clean lines and adjust their cached line b
reak information | 1259 // Now we have to walk all of the clean lines and adjust their cached line b
reak information |
1264 // to reflect our updated offsets. | 1260 // to reflect our updated offsets. |
1265 if (lastRootBox) | 1261 if (lastRootBox) |
1266 lastRootBox = lastRootBox->nextRootBox(); | 1262 lastRootBox = lastRootBox->nextRootBox(); |
1267 if (firstRootBox) { | 1263 if (firstRootBox) { |
1268 RootInlineBox* prev = firstRootBox->prevRootBox(); | 1264 RootInlineBox* prev = firstRootBox->prevRootBox(); |
1269 if (prev) | 1265 if (prev) |
1270 firstRootBox = prev; | 1266 firstRootBox = prev; |
1271 } else if (lastTextBox()) { | 1267 } else if (lastTextBox()) { |
1272 ASSERT(!lastRootBox); | 1268 ASSERT(!lastRootBox); |
1273 firstRootBox = lastTextBox()->root(); | 1269 firstRootBox = &lastTextBox()->root(); |
1274 firstRootBox->markDirty(); | 1270 firstRootBox->markDirty(); |
1275 dirtiedLines = true; | 1271 dirtiedLines = true; |
1276 } | 1272 } |
1277 for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr =
curr->nextRootBox()) { | 1273 for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr =
curr->nextRootBox()) { |
1278 if (curr->lineBreakObj() == this && curr->lineBreakPos() > end) | 1274 if (curr->lineBreakObj() == this && curr->lineBreakPos() > end) |
1279 curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta)); | 1275 curr->setLineBreakPos(clampToInteger(curr->lineBreakPos() + delta)); |
1280 } | 1276 } |
1281 | 1277 |
1282 // If the text node is empty, dirty the line where new text will be inserted
. | 1278 // If the text node is empty, dirty the line where new text will be inserted
. |
1283 if (!firstTextBox() && parent()) { | 1279 if (!firstTextBox() && parent()) { |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1866 } | 1862 } |
1867 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); | 1863 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); |
1868 } | 1864 } |
1869 | 1865 |
1870 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox() | 1866 PassRefPtr<AbstractInlineTextBox> RenderText::firstAbstractInlineTextBox() |
1871 { | 1867 { |
1872 return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox); | 1868 return AbstractInlineTextBox::getOrCreate(this, m_firstTextBox); |
1873 } | 1869 } |
1874 | 1870 |
1875 } // namespace WebCore | 1871 } // namespace WebCore |
OLD | NEW |