📄 visibleposition.cpp
字号:
/* * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "VisiblePosition.h"#include "CString.h"#include "Document.h"#include "Element.h"#include "FloatQuad.h"#include "HTMLNames.h"#include "InlineTextBox.h"#include "Logging.h"#include "Range.h"#include "Text.h"#include "htmlediting.h"#include "visible_units.h"#include <stdio.h>namespace WebCore {using namespace HTMLNames;VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity){ init(pos, affinity);}VisiblePosition::VisiblePosition(Node *node, int offset, EAffinity affinity){ ASSERT(offset >= 0); init(Position(node, offset), affinity);}void VisiblePosition::init(const Position& position, EAffinity affinity){ m_affinity = affinity; m_deepPosition = canonicalPosition(position); // When not at a line wrap, make sure to end up with DOWNSTREAM affinity. if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this))) m_affinity = DOWNSTREAM;}VisiblePosition VisiblePosition::next(bool stayInEditableContent) const{ VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity); if (!stayInEditableContent) return next; return honorEditableBoundaryAtOrAfter(next);}VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const{ // find first previous DOM position that is visible Position pos = previousVisuallyDistinctCandidate(m_deepPosition); // return null visible position if there is no previous visible position if (pos.atStart()) return VisiblePosition(); VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM); ASSERT(prev != *this); #ifndef NDEBUG // we should always be able to make the affinity DOWNSTREAM, because going previous from an // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!). if (prev.isNotNull() && m_affinity == UPSTREAM) { VisiblePosition temp = prev; temp.setAffinity(UPSTREAM); ASSERT(inSameLine(temp, prev)); }#endif if (!stayInEditableContent) return prev; return honorEditableBoundaryAtOrBefore(prev);}Position VisiblePosition::leftVisuallyDistinctCandidate() const{ Position p = m_deepPosition; if (!p.node()) return Position(); Position downstreamStart = p.downstream(); TextDirection primaryDirection = LTR; for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) { if (r->isBlockFlow()) { primaryDirection = r->style()->direction(); break; } } while (true) { InlineBox* box; int offset; p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset); if (!box) return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); RenderObject* renderer = box->renderer(); while (true) { if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset()) return box->direction() == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); offset = box->direction() == LTR ? renderer->previousOffset(offset) : renderer->nextOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->direction() == LTR ? offset < caretMinOffset : offset > caretMaxOffset) { // Overshot to the left. InlineBox* prevBox = box->prevLeafChild(); if (!prevBox) return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition); // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = prevBox; renderer = box->renderer(); offset = prevBox->caretRightmostOffset(); continue; } ASSERT(offset == box->caretLeftmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* prevBox = box->prevLeafChild(); if (box->direction() == primaryDirection) { if (!prevBox || prevBox->bidiLevel() >= level) break; level = prevBox->bidiLevel(); InlineBox* nextBox = box; do { nextBox = nextBox->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (nextBox && nextBox->bidiLevel() == level) break; while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } renderer = box->renderer(); offset = box->caretRightmostOffset(); if (box->direction() == primaryDirection) break; continue; } if (prevBox) { box = prevBox; renderer = box->renderer(); offset = box->caretRightmostOffset(); if (box->bidiLevel() > level) { do { prevBox = box->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (!prevBox || prevBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) { while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); } renderer = box->renderer(); offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset(); } break; } p = Position(renderer->node(), offset); if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd()) return p; }}VisiblePosition VisiblePosition::left(bool stayInEditableContent) const{ Position pos = leftVisuallyDistinctCandidate(); if (pos.atStart() || pos.atEnd()) return VisiblePosition(); VisiblePosition left = VisiblePosition(pos, DOWNSTREAM); ASSERT(left != *this); if (!stayInEditableContent) return left; // FIXME: This may need to do something different from "before". return honorEditableBoundaryAtOrBefore(left);}Position VisiblePosition::rightVisuallyDistinctCandidate() const{ Position p = m_deepPosition; if (!p.node()) return Position(); Position downstreamStart = p.downstream(); TextDirection primaryDirection = LTR; for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) { if (r->isBlockFlow()) { primaryDirection = r->style()->direction(); break; } } while (true) { InlineBox* box; int offset; p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); RenderObject* renderer = box->renderer(); while (true) { if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset()) return box->direction() == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); offset = box->direction() == LTR ? renderer->nextOffset(offset) : renderer->previousOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->direction() == LTR ? offset > caretMaxOffset : offset < caretMinOffset) { // Overshot to the right. InlineBox* nextBox = box->nextLeafChild(); if (!nextBox) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = nextBox; renderer = box->renderer(); offset = nextBox->caretLeftmostOffset(); continue; } ASSERT(offset == box->caretRightmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* nextBox = box->nextLeafChild(); if (box->direction() == primaryDirection) { if (!nextBox || nextBox->bidiLevel() >= level) break; level = nextBox->bidiLevel(); InlineBox* prevBox = box; do { prevBox = prevBox->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA break; // For example, abc 123 ^ CBA while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } renderer = box->renderer(); offset = box->caretLeftmostOffset(); if (box->direction() == primaryDirection) break; continue; } if (nextBox) { box = nextBox; renderer = box->renderer(); offset = box->caretLeftmostOffset(); if (box->bidiLevel() > level) { do { nextBox = box->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (!nextBox || nextBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -