📄 dom_selection.cpp
字号:
/* * Copyright (C) 2004 Apple Computer, 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 "dom_selection.h"#include "htmltags.h"#include "khtml_part.h"#include "khtmlview.h"#include "qevent.h"#include "qpainter.h"#include "qrect.h"#include "dom/dom2_range.h"#include "dom/dom_node.h"#include "dom/dom_string.h"#include "rendering/render_object.h"#include "rendering/render_style.h"#include "rendering/render_text.h"#include "xml/dom_docimpl.h"#include "xml/dom_positioniterator.h"#include "xml/dom_elementimpl.h"#include "xml/dom_nodeimpl.h"#include "xml/dom_textimpl.h"#if KWIQ#include <stdio.h>#endif#if APPLE_CHANGES#include "KWQAssertions.h"#else#define ASSERT(assertion) assert(assertion)#endif#define EDIT_DEBUG 0using khtml::findWordBoundary;using khtml::InlineTextBox;using khtml::RenderObject;using khtml::RenderText;namespace DOM {static bool firstRunAt(RenderObject *renderNode, int y, NodeImpl *&startNode, long &startOffset);static bool lastRunAt(RenderObject *renderNode, int y, NodeImpl *&endNode, long &endOffset);static bool startAndEndLineNodesIncludingNode(NodeImpl *node, int offset, Selection &selection);static inline Position &emptyPosition(){ static Position EmptyPosition = Position(); return EmptyPosition;}Selection::Selection(){ init();}Selection::Selection(const Position &pos){ init(); assignBaseAndExtent(pos, pos); validate();}Selection::Selection(const Range &r){ const Position start(r.startContainer().handle(), r.startOffset()); const Position end(r.endContainer().handle(), r.endOffset()); init(); assignBaseAndExtent(start, end); validate();}Selection::Selection(const Position &base, const Position &extent){ init(); assignBaseAndExtent(base, extent); validate();}Selection::Selection(const Selection &o){ init(); assignBaseAndExtent(o.base(), o.extent()); assignStartAndEnd(o.start(), o.end()); m_state = o.m_state; m_affinity = o.m_affinity; m_baseIsStart = o.m_baseIsStart; m_needsCaretLayout = o.m_needsCaretLayout; m_modifyBiasSet = o.m_modifyBiasSet; // Only copy the coordinates over if the other object // has had a layout, otherwise keep the current // coordinates. This prevents drawing artifacts from // remaining when the caret is painted and then moves, // and the old rectangle needs to be repainted. if (!m_needsCaretLayout) { m_caretX = o.m_caretX; m_caretY = o.m_caretY; m_caretSize = o.m_caretSize; }}void Selection::init(){ m_base = m_extent = m_start = m_end = emptyPosition(); m_state = NONE; m_caretX = 0; m_caretY = 0; m_caretSize = 0; m_baseIsStart = true; m_needsCaretLayout = true; m_modifyBiasSet = false; m_affinity = DOWNSTREAM;}Selection &Selection::operator=(const Selection &o){ assignBaseAndExtent(o.base(), o.extent()); assignStartAndEnd(o.start(), o.end()); m_state = o.m_state; m_affinity = o.m_affinity; m_baseIsStart = o.m_baseIsStart; m_needsCaretLayout = o.m_needsCaretLayout; m_modifyBiasSet = o.m_modifyBiasSet; // Only copy the coordinates over if the other object // has had a layout, otherwise keep the current // coordinates. This prevents drawing artifacts from // remaining when the caret is painted and then moves, // and the old rectangle needs to be repainted. if (!m_needsCaretLayout) { m_caretX = o.m_caretX; m_caretY = o.m_caretY; m_caretSize = o.m_caretSize; } return *this;}void Selection::setAffinity(EAffinity affinity){ if (affinity == m_affinity) return; m_affinity = affinity; setNeedsLayout();}void Selection::moveTo(const Range &r){ Position start(r.startContainer().handle(), r.startOffset()); Position end(r.endContainer().handle(), r.endOffset()); moveTo(start, end);}void Selection::moveTo(const Selection &o){ moveTo(o.start(), o.end());}void Selection::moveTo(const Position &pos){ moveTo(pos, pos);}void Selection::moveTo(const Position &base, const Position &extent){ assignBaseAndExtent(base, extent); validate();}bool Selection::modify(EAlter alter, EDirection dir, ETextGranularity granularity){ Position pos; switch (dir) { // EDIT FIXME: This needs to handle bidi case RIGHT: case FORWARD: if (alter == EXTEND) { if (!m_modifyBiasSet) { m_modifyBiasSet = true; assignBaseAndExtent(start(), end()); } switch (granularity) { case CHARACTER: pos = extent().nextCharacterPosition(); break; case WORD: pos = extent().nextWordPosition(); break; case LINE: pos = extent().nextLinePosition(xPosForVerticalArrowNavigation(EXTENT)); break; case PARAGRAPH: // not implemented break; } } else { m_modifyBiasSet = false; switch (granularity) { case CHARACTER: pos = (state() == RANGE) ? end() : extent().nextCharacterPosition(); break; case WORD: pos = extent().nextWordPosition(); break; case LINE: pos = end().nextLinePosition(xPosForVerticalArrowNavigation(END, state() == RANGE)); break; case PARAGRAPH: // not implemented break; } } break; // EDIT FIXME: This needs to handle bidi case LEFT: case BACKWARD: if (alter == EXTEND) { if (!m_modifyBiasSet) { m_modifyBiasSet = true; assignBaseAndExtent(end(), start()); } switch (granularity) { case CHARACTER: pos = extent().previousCharacterPosition(); break; case WORD: pos = extent().previousWordPosition(); break; case LINE: pos = extent().previousLinePosition(xPosForVerticalArrowNavigation(EXTENT)); break; case PARAGRAPH: // not implemented break; } } else { m_modifyBiasSet = false; switch (granularity) { case CHARACTER: pos = (state() == RANGE) ? start() : extent().previousCharacterPosition(); break; case WORD: pos = extent().previousWordPosition(); break; case LINE: pos = start().previousLinePosition(xPosForVerticalArrowNavigation(START, state() == RANGE)); break; case PARAGRAPH: // not implemented break; } } break; } if (pos.isEmpty()) return false; if (alter == MOVE) moveTo(pos); else // alter == EXTEND setExtent(pos); return true;}bool Selection::expandUsingGranularity(ETextGranularity granularity){ if (state() == NONE) return false; validate(granularity); return true;}int Selection::xPosForVerticalArrowNavigation(EPositionType type, bool recalc) const{ int x = 0; if (state() == NONE) return x; Position pos; switch (type) { case START: pos = start(); break; case END: pos = end();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -