Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(741)

Unified Diff: Source/core/dom/Position.cpp

Issue 20681004: Make first-letter style to work with editing Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: 2013-08-08T13:29:08 Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/dom/Position.h ('k') | Source/core/dom/PositionIterator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/dom/Position.cpp
diff --git a/Source/core/dom/Position.cpp b/Source/core/dom/Position.cpp
index c917fb5bf97a64c57766a55d202d19a370c2d1c6..7aaad8f3763b03fcd163760beb468c559717f566 100644
--- a/Source/core/dom/Position.cpp
+++ b/Source/core/dom/Position.cpp
@@ -42,7 +42,7 @@
#include "core/rendering/InlineTextBox.h"
#include "core/rendering/RenderBlock.h"
#include "core/rendering/RenderInline.h"
-#include "core/rendering/RenderText.h"
+#include "core/rendering/RenderTextFragment.h"
#include "wtf/text/CString.h"
#include "wtf/unicode/CharacterNames.h"
@@ -457,16 +457,45 @@ bool Position::atEndOfTree() const
return !findParent(deprecatedNode()) && m_offset >= lastOffsetForEditing(deprecatedNode());
}
-int Position::renderedOffset() const
+RenderObject* Position::renderer() const
{
- if (!deprecatedNode()->isTextNode())
- return m_offset;
+ if (!m_anchorNode)
+ return 0;
+ RenderObject* renderer = m_anchorNode->renderer();
eseidel 2013/09/09 20:28:27 Positions can be relative to anchor nodes other th
yosin_UTC9 2013/09/20 09:30:26 This function is replacement of Position.anchorNod
+ if (!renderer || !renderer->isText() || !toRenderText(renderer)->isTextFragment())
+ return renderer;
+ if (m_offset >= static_cast<int>(toRenderTextFragment(renderer)->textStartOffset()))
+ return renderer;
+ return toRenderTextFragment(renderer)->firstRenderTextInFirstLetter();
+}
+
+int Position::offsetInRenderer() const
+{
+ switch (m_isLegacyEditingPosition ? PositionIsOffsetInAnchor : m_anchorType) {
+ case PositionIsBeforeChildren:
+ case PositionIsBeforeAnchor:
eseidel 2013/09/09 20:28:27 Wouldn't this possibly have a different renderer d
yosin_UTC9 2013/09/20 09:30:26 This function does as same as deprecatedEditingOff
+ case PositionIsOffsetInAnchor: {
+ RenderObject* renderer = this->renderer();
+ if (!renderer || !renderer->isText())
+ return m_offset;
+ return m_offset - toRenderText(renderer)->textStartOffset();
+ }
+ case PositionIsAfterChildren:
+ case PositionIsAfterAnchor:
+ return offsetForPositionAfterAnchor();
+ }
+ ASSERT_NOT_REACHED();
+ return m_offset;
+}
- if (!deprecatedNode()->renderer())
+int Position::renderedOffset() const
+{
+ RenderObject* renderer = this->renderer();
+ if (!renderer || !renderer->isText())
return m_offset;
- int result = 0;
- RenderText* textRenderer = toRenderText(deprecatedNode()->renderer());
+ RenderText* textRenderer = toRenderText(renderer);
+ int result = textRenderer->textStartOffset();
for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
int start = box->start();
int end = box->start() + box->len();
@@ -596,14 +625,17 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
PositionIterator currentPos = lastVisible;
bool startEditable = startNode->rendererIsEditable();
+ RenderObject* startRenderer = renderer();
Node* lastNode = startNode;
+ RenderObject* lastRenderer = startRenderer;
bool boundaryCrossed = false;
for (; !currentPos.atStart(); currentPos.decrement()) {
Node* currentNode = currentPos.node();
+ RenderObject* currentRenderer = currentPos.renderer();
// Don't check for an editability change if we haven't moved to a different node,
// to avoid the expense of computing rendererIsEditable().
- if (currentNode != lastNode) {
+ if (currentRenderer != lastRenderer) {
// Don't change editability.
bool currentEditable = currentNode->rendererIsEditable();
if (startEditable != currentEditable) {
@@ -612,6 +644,7 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
boundaryCrossed = true;
}
lastNode = currentNode;
+ lastRenderer = currentPos.renderer();
}
// If we've moved to a position that is visually distinct, return the last saved position. There
@@ -620,8 +653,7 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
return lastVisible;
// skip position in unrendered or invisible node
- RenderObject* renderer = currentNode->renderer();
- if (!renderer || renderer->style()->visibility() != VISIBLE)
+ if (!currentRenderer || currentRenderer->style()->visibility() != VISIBLE)
continue;
if (rule == CanCrossEditingBoundary && boundaryCrossed) {
@@ -646,18 +678,12 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
}
// return current position if it is in rendered text
- if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
- if (currentNode != startNode) {
- // This assertion fires in layout tests in the case-transform.html test because
- // of a mix-up between offsets in the text in the DOM tree with text in the
- // render tree which can have a different length due to case transformation.
- // Until we resolve that, disable this so we can run the layout tests!
- //ASSERT(currentOffset >= renderer->caretMaxOffset());
- return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
- }
+ if (currentRenderer->isText() && toRenderText(currentRenderer)->firstTextBox()) {
+ RenderText* textRenderer = toRenderText(currentRenderer);
+ if (currentRenderer != startRenderer)
+ return createLegacyEditingPosition(currentNode, textRenderer->caretMaxOffset() + textRenderer->textStartOffset());
- unsigned textOffset = currentPos.offsetInLeafNode();
- RenderText* textRenderer = toRenderText(renderer);
+ unsigned textOffset = currentPos.offsetInLeafNode() - textRenderer->textStartOffset();
InlineTextBox* lastTextBox = textRenderer->lastTextBox();
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset <= box->start() + box->len()) {
@@ -719,14 +745,17 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
PositionIterator currentPos = lastVisible;
bool startEditable = startNode->rendererIsEditable();
+ RenderObject* startRenderer = renderer();
Node* lastNode = startNode;
+ RenderObject* lastRenderer = startRenderer;
bool boundaryCrossed = false;
for (; !currentPos.atEnd(); currentPos.increment()) {
Node* currentNode = currentPos.node();
+ RenderObject* currentRenderer = currentPos.renderer();
// Don't check for an editability change if we haven't moved to a different node,
// to avoid the expense of computing rendererIsEditable().
- if (currentNode != lastNode) {
+ if (currentRenderer!= lastRenderer) {
// Don't change editability.
bool currentEditable = currentNode->rendererIsEditable();
if (startEditable != currentEditable) {
@@ -736,6 +765,7 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
}
lastNode = currentNode;
+ lastRenderer = currentRenderer;
}
// stop before going above the body, up into the head
@@ -753,8 +783,7 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
return lastVisible;
// skip position in unrendered or invisible node
- RenderObject* renderer = currentNode->renderer();
- if (!renderer || renderer->style()->visibility() != VISIBLE)
+ if (!currentRenderer || currentRenderer->style()->visibility() != VISIBLE)
continue;
if (rule == CanCrossEditingBoundary && boundaryCrossed) {
@@ -768,20 +797,18 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
// Return position before tables and nodes which have content that can be ignored.
if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
- if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
- return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
+ if (currentPos.offsetInLeafNode() <= currentRenderer->caretMinOffset())
+ return createLegacyEditingPosition(currentNode, currentRenderer->caretMinOffset());
continue;
}
// return current position if it is in rendered text
- if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
- if (currentNode != startNode) {
- ASSERT(currentPos.atStartOfNode());
- return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
- }
+ if (currentRenderer->isText() && toRenderText(currentRenderer)->firstTextBox()) {
+ RenderText* textRenderer = toRenderText(currentRenderer);
+ if (currentRenderer != startRenderer)
+ return createLegacyEditingPosition(currentNode, textRenderer->caretMinOffset() + textRenderer->textStartOffset());
- unsigned textOffset = currentPos.offsetInLeafNode();
- RenderText* textRenderer = toRenderText(renderer);
+ unsigned textOffset = currentPos.offsetInLeafNode() - textRenderer->textStartOffset();
InlineTextBox* lastTextBox = textRenderer->lastTextBox();
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset <= box->end()) {
@@ -842,9 +869,16 @@ bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* render
return false;
}
+// FIXME: Caller of nodeIsUserSelectNode() should consider first letter and
+// remaining text have different user-select CSS property.
bool Position::nodeIsUserSelectNone(Node* node)
{
- return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE && node->renderer()->style()->userModify() == READ_ONLY;
+ return node && rendererIsUserSelectNone(node->renderer());
+}
+
+bool Position::rendererIsUserSelectNone(RenderObject* renderer)
+{
+ return renderer && renderer->style()->userSelect() == SELECT_NONE && renderer->style()->userModify() == READ_ONLY;
}
ContainerNode* Position::findParent(const Node* node)
@@ -883,10 +917,7 @@ Node* Position::rootUserSelectAllForNode(Node* node)
bool Position::isCandidate() const
{
- if (isNull())
- return false;
-
- RenderObject* renderer = deprecatedNode()->renderer();
+ RenderObject* renderer = this->renderer();
if (!renderer)
return false;
@@ -898,7 +929,7 @@ bool Position::isCandidate() const
return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
if (renderer->isText())
- return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
+ return !rendererIsUserSelectNone(renderer) && inRenderedText();
if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
@@ -920,24 +951,23 @@ bool Position::isCandidate() const
bool Position::inRenderedText() const
{
- if (isNull() || !deprecatedNode()->isTextNode())
+ RenderObject* renderer = this->renderer();
+ if (!renderer || !renderer->isText())
return false;
- RenderObject* renderer = deprecatedNode()->renderer();
- if (!renderer)
- return false;
-
- RenderText *textRenderer = toRenderText(renderer);
+ RenderText* textRenderer = toRenderText(renderer);
+ int offset = m_offset - textRenderer->textStartOffset();
for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
+ if (offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
// The offset we're looking for is before this node
// this means the offset must be in content that is
// not rendered. Return false.
return false;
}
- if (box->containsCaretOffset(m_offset))
+ if (box->containsCaretOffset(offset)) {
// Return false for offsets inside composed characters.
- return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
+ return !offset || offset == textRenderer->nextOffset(textRenderer->previousOffset(offset));
+ }
}
return false;
@@ -945,22 +975,20 @@ bool Position::inRenderedText() const
bool Position::isRenderedCharacter() const
{
- if (isNull() || !deprecatedNode()->isTextNode())
- return false;
-
- RenderObject* renderer = deprecatedNode()->renderer();
- if (!renderer)
+ RenderObject* renderer = this->renderer();
+ if (!renderer || !renderer->isText())
return false;
RenderText* textRenderer = toRenderText(renderer);
+ int offset = m_offset - textRenderer->textStartOffset();
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
+ if (offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
// The offset we're looking for is before this node
// this means the offset must be in content that is
// not rendered. Return false.
return false;
}
- if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
+ if (offset >= static_cast<int>(box->start()) && offset < static_cast<int>(box->start() + box->len()))
return true;
}
@@ -969,14 +997,11 @@ bool Position::isRenderedCharacter() const
bool Position::rendersInDifferentPosition(const Position &pos) const
{
- if (isNull() || pos.isNull())
- return false;
-
- RenderObject* renderer = deprecatedNode()->renderer();
+ RenderObject* renderer = this->renderer();
if (!renderer)
return false;
- RenderObject* posRenderer = pos.deprecatedNode()->renderer();
+ RenderObject* posRenderer = pos.renderer();
if (!posRenderer)
return false;
@@ -1157,7 +1182,7 @@ static Position upstreamIgnoringEditingBoundaries(Position position)
void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
{
caretOffset = deprecatedEditingOffset();
- RenderObject* renderer = deprecatedNode()->renderer();
+ RenderObject* renderer = this->renderer();
if (!renderer->isText()) {
inlineBox = 0;
@@ -1186,6 +1211,16 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
InlineTextBox* box;
InlineTextBox* candidate = 0;
+ if (textRenderer->isTextFragment() && toRenderTextFragment(textRenderer)->firstLetter()) {
+ if (caretOffset) {
+ caretOffset -= textRenderer->textStartOffset();
+ } else {
+ textRenderer = toRenderTextFragment(textRenderer)->firstRenderTextInFirstLetter();
+ if (!textRenderer)
+ return;
+ }
+ }
+
for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
int caretMinOffset = box->caretMinOffset();
int caretMaxOffset = box->caretMaxOffset();
« no previous file with comments | « Source/core/dom/Position.h ('k') | Source/core/dom/PositionIterator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698