?? selection.cpp
字號:
setModifyBias(alter, dir);
VisiblePosition pos;
switch (dir) {
// EDIT FIXME: These need to handle bidi
case RIGHT:
case FORWARD:
if (alter == EXTEND)
pos = modifyExtendingRightForward(granularity);
else
pos = modifyMovingRightForward(granularity);
break;
case LEFT:
case BACKWARD:
if (alter == EXTEND)
pos = modifyExtendingLeftBackward(granularity);
else
pos = modifyMovingLeftBackward(granularity);
break;
}
if (pos.isNull())
return false;
switch (alter) {
case MOVE:
moveTo(pos);
break;
case EXTEND:
setExtent(pos);
break;
}
setNeedsLayout();
return true;
}
// FIXME: Maybe baseline would be better?
static bool caretY(const VisiblePosition &c, int &y)
{
Position p = c.deepEquivalent();
NodeImpl *n = p.node();
if (!n)
return false;
RenderObject *r = p.node()->renderer();
if (!r)
return false;
QRect rect = r->caretRect(p.offset());
if (rect.isEmpty())
return false;
y = rect.y() + rect.height() / 2;
return true;
}
bool Selection::modify(EAlter alter, int verticalDistance)
{
if (verticalDistance == 0)
return false;
bool up = verticalDistance < 0;
if (up)
verticalDistance = -verticalDistance;
// can dump this UPSTREAM when we have m_extentAffinity
m_affinity = UPSTREAM;
setModifyBias(alter, up ? BACKWARD : FORWARD);
VisiblePosition pos;
int xPos = 0;
switch (alter) {
case MOVE:
pos = VisiblePosition(up ? m_start : m_end, m_affinity);
xPos = xPosForVerticalArrowNavigation(up ? START : END, isRange());
break;
case EXTEND:
pos = VisiblePosition(m_extent, m_affinity);
xPos = xPosForVerticalArrowNavigation(EXTENT);
break;
}
int startY;
if (!caretY(pos, startY))
return false;
if (up)
startY = -startY;
int lastY = startY;
VisiblePosition result;
VisiblePosition next;
for (VisiblePosition p = pos; ; p = next) {
next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
if (next.isNull() || next == p)
break;
int nextY;
if (!caretY(next, nextY))
break;
if (up)
nextY = -nextY;
if (nextY - startY > verticalDistance)
break;
if (nextY >= lastY) {
lastY = nextY;
result = next;
}
}
if (result.isNull())
return false;
switch (alter) {
case MOVE:
moveTo(result);
break;
case EXTEND:
setExtent(result);
break;
}
return true;
}
bool Selection::expandUsingGranularity(ETextGranularity granularity)
{
if (isNone())
return false;
validate(granularity);
return true;
}
int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const
{
int x = 0;
if (isNone())
return x;
Position pos;
switch (type) {
case START:
pos = m_start;
break;
case END:
pos = m_end;
break;
case BASE:
pos = m_base;
break;
case EXTENT:
pos = m_extent;
break;
}
KHTMLPart *part = pos.node()->getDocument()->part();
if (!part)
return x;
if (recalc || part->xPosForVerticalArrowNavigation() == KHTMLPart::NoXPosForVerticalArrowNavigation) {
switch (m_affinity) {
case DOWNSTREAM:
pos = VisiblePosition(pos, m_affinity).downstreamDeepEquivalent();
break;
case UPSTREAM:
pos = VisiblePosition(pos, m_affinity).deepEquivalent();
break;
}
x = pos.node()->renderer()->caretRect(pos.offset(), m_affinity).x();
part->setXPosForVerticalArrowNavigation(x);
}
else {
x = part->xPosForVerticalArrowNavigation();
}
return x;
}
void Selection::clear()
{
m_affinity = SEL_DEFAULT_AFFINITY;
m_base.clear();
m_extent.clear();
validate();
}
void Selection::setBase(const VisiblePosition &pos)
{
m_affinity = pos.affinity();
m_base = pos.deepEquivalent();
validate();
}
void Selection::setExtent(const VisiblePosition &pos)
{
// FIXME: Support extentAffinity
m_extent = pos.deepEquivalent();
validate();
}
void Selection::setBaseAndExtent(const VisiblePosition &base, const VisiblePosition &extent)
{
// FIXME: Support extentAffinity
m_affinity = base.affinity();
m_base = base.deepEquivalent();
m_extent = extent.deepEquivalent();
validate();
}
void Selection::setBase(const Position &pos, EAffinity baseAffinity)
{
m_affinity = baseAffinity;
m_base = pos;
validate();
}
void Selection::setExtent(const Position &pos, EAffinity extentAffinity)
{
// FIXME: Support extentAffinity for real
m_affinity = extentAffinity;
m_extent = pos;
validate();
}
void Selection::setBaseAndExtent(const Position &base, EAffinity baseAffinity, const Position &extent, EAffinity extentAffinity)
{
// FIXME: extentAffinity
m_affinity = baseAffinity;
m_base = base;
m_extent = extent;
validate();
}
void Selection::setNeedsLayout(bool flag)
{
m_needsLayout = flag;
}
Range Selection::toRange() const
{
if (isNone())
return Range();
// Make sure we have an updated layout since this function is called
// in the course of running edit commands which modify the DOM.
// Failing to call this can result in equivalentXXXPosition calls returning
// incorrect results.
m_start.node()->getDocument()->updateLayout();
Position s, e;
if (isCaret()) {
// If the selection is a caret, move the range start upstream. This helps us match
// the conventions of text editors tested, which make style determinations based
// on the character before the caret, if any.
s = m_start.upstream(StayInBlock).equivalentRangeCompliantPosition();
e = s;
}
else {
// If the selection is a range, select the minimum range that encompasses the selection.
// Again, this is to match the conventions of text editors tested, which make style
// determinations based on the first character of the selection.
// For instance, this operation helps to make sure that the "X" selected below is the
// only thing selected. The range should not be allowed to "leak" out to the end of the
// previous text node, or to the beginning of the next text node, each of which has a
// different style.
//
// On a treasure map, <b>X</b> marks the spot.
// ^ selected
//
ASSERT(isRange());
s = m_start.downstream(StayInBlock);
e = m_end.upstream(StayInBlock);
if (RangeImpl::compareBoundaryPoints(s.node(), s.offset(), e.node(), e.offset()) > 0) {
// Make sure the start is before the end.
// The end can wind up before the start if collapsed whitespace is the only thing selected.
Position tmp = s;
s = e;
e = tmp;
}
s = s.equivalentRangeCompliantPosition();
e = e.equivalentRangeCompliantPosition();
}
// Use this roundabout way of creating the Range in order to have defined behavior
// when there is a DOM exception.
int exceptionCode = 0;
Range result(s.node()->getDocument());
RangeImpl *handle = result.handle();
ASSERT(handle);
handle->setStart(s.node(), s.offset(), exceptionCode);
if (exceptionCode) {
ERROR("Exception setting Range start from Selection: %d", exceptionCode);
return Range();
}
handle->setEnd(e.node(), e.offset(), exceptionCode);
if (exceptionCode) {
ERROR("Exception setting Range end from Selection: %d", exceptionCode);
return Range();
}
return result;
}
void Selection::layout()
{
if (isNone() || !m_start.node()->inDocument() || !m_end.node()->inDocument()) {
m_caretRect = QRect();
m_expectedVisibleRect = QRect();
return;
}
m_start.node()->getDocument()->updateRendering();
if (isCaret()) {
Position pos = m_start;
switch (m_affinity) {
case DOWNSTREAM:
pos = VisiblePosition(m_start, m_affinity).downstreamDeepEquivalent();
break;
case UPSTREAM:
pos = VisiblePosition(m_start, m_affinity).deepEquivalent();
break;
}
if (pos.isNotNull()) {
ASSERT(pos.node()->renderer());
m_caretRect = pos.node()->renderer()->caretRect(pos.offset(), m_affinity);
m_expectedVisibleRect = m_caretRect;
}
else {
m_caretRect = QRect();
m_expectedVisibleRect = QRect();
}
}
else {
// Calculate which position to use based on whether the base is the start.
// We want the position, start or end, that was calculated using the extent.
// This makes the selection follow the extent position while scrolling as a
// result of arrow navigation.
//
// Note: no need to get additional help from VisiblePosition. The m_start and
// m_end positions should already be visible, and we're only interested in
// a rectangle for m_expectedVisibleRect, hence affinity is not a factor
// like it is when drawing a caret.
//
Position pos = m_baseIsStart ? m_end : m_start;
ASSERT(pos.node()->renderer());
m_expectedVisibleRect = pos.node()->renderer()->caretRect(pos.offset(), m_affinity);
m_caretRect = QRect();
}
m_needsLayout = false;
}
QRect Selection::caretRect() const
{
if (m_needsLayout) {
const_cast<Selection *>(this)->layout();
}
return m_caretRect;
}
QRect Selection::expectedVisibleRect() const
{
if (m_needsLayout) {
const_cast<Selection *>(this)->layout();
}
return m_expectedVisibleRect;
}
QRect Selection::caretRepaintRect() const
{
// FIXME: Add one pixel of slop on each side to make sure we don't leave behind artifacts.
QRect r = caretRect();
if (r.isEmpty())
return QRect();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -