This source file includes following definitions.
- m_caretVisibility
- create
- isContentRichlyEditable
- setCaretPosition
- removingNodeRemovesPosition
- nodeWillBeRemoved
- clearCaretRect
- caretRendersInsideNode
- caretRenderer
- updateCaretRect
- caretRenderer
- absoluteBoundsForLocalRect
- repaintCaretForLocalRect
- shouldRepaintCaret
- invalidateCaretRect
- paintCaret
- paintDragCaret
#include "config.h"
#include "core/editing/Caret.h"
#include "core/dom/Document.h"
#include "core/editing/htmlediting.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/rendering/RenderBlock.h"
#include "core/rendering/RenderView.h"
namespace WebCore {
CaretBase::CaretBase(CaretVisibility visibility)
: m_caretRectNeedsUpdate(true)
, m_caretVisibility(visibility)
{
}
DragCaretController::DragCaretController()
: CaretBase(Visible)
{
}
PassOwnPtr<DragCaretController> DragCaretController::create()
{
return adoptPtr(new DragCaretController);
}
bool DragCaretController::isContentRichlyEditable() const
{
return isRichlyEditablePosition(m_position.deepEquivalent());
}
void DragCaretController::setCaretPosition(const VisiblePosition& position)
{
if (Node* node = m_position.deepEquivalent().deprecatedNode())
invalidateCaretRect(node);
m_position = position;
setCaretRectNeedsUpdate();
Document* document = 0;
if (Node* node = m_position.deepEquivalent().deprecatedNode()) {
invalidateCaretRect(node);
document = &node->document();
}
if (m_position.isNull() || m_position.isOrphan())
clearCaretRect();
else
updateCaretRect(document, m_position);
}
static bool removingNodeRemovesPosition(Node& node, const Position& position)
{
if (!position.anchorNode())
return false;
if (position.anchorNode() == node)
return true;
if (!node.isElementNode())
return false;
Element& element = toElement(node);
return element.containsIncludingShadowDOM(position.anchorNode());
}
void DragCaretController::nodeWillBeRemoved(Node& node)
{
if (!hasCaret() || !node.inActiveDocument())
return;
if (!removingNodeRemovesPosition(node, m_position.deepEquivalent()))
return;
m_position.deepEquivalent().document()->renderView()->clearSelection();
clear();
}
void CaretBase::clearCaretRect()
{
m_caretLocalRect = LayoutRect();
}
static inline bool caretRendersInsideNode(Node* node)
{
return node && !isRenderedTable(node) && !editingIgnoresContent(node);
}
RenderObject* CaretBase::caretRenderer(Node* node)
{
if (!node)
return 0;
RenderObject* renderer = node->renderer();
if (!renderer)
return 0;
bool paintedByBlock = renderer->isRenderBlock() && caretRendersInsideNode(node);
return paintedByBlock ? renderer : renderer->containingBlock();
}
bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caretPosition)
{
document->updateRenderTreeIfNeeded();
m_caretLocalRect = LayoutRect();
m_caretRectNeedsUpdate = false;
if (caretPosition.isNull())
return false;
ASSERT(caretPosition.deepEquivalent().deprecatedNode()->renderer());
RenderObject* renderer;
LayoutRect localRect = caretPosition.localCaretRect(renderer);
RenderObject* caretPainter = caretRenderer(caretPosition.deepEquivalent().deprecatedNode());
bool unrooted = false;
while (renderer != caretPainter) {
RenderObject* containerObject = renderer->container();
if (!containerObject) {
unrooted = true;
break;
}
localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
renderer = containerObject;
}
if (!unrooted)
m_caretLocalRect = localRect;
return true;
}
RenderObject* DragCaretController::caretRenderer() const
{
return CaretBase::caretRenderer(m_position.deepEquivalent().deprecatedNode());
}
IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) const
{
RenderObject* caretPainter = caretRenderer(node);
if (!caretPainter)
return IntRect();
LayoutRect localRect(rect);
if (caretPainter->isBox())
toRenderBox(caretPainter)->flipForWritingMode(localRect);
return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
}
void CaretBase::repaintCaretForLocalRect(Node* node, const LayoutRect& rect)
{
RenderObject* caretPainter = caretRenderer(node);
if (!caretPainter)
return;
LayoutRect inflatedRect = rect;
inflatedRect.inflate(1);
caretPainter->repaintRectangle(inflatedRect);
}
bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditable) const
{
ASSERT(view);
bool caretBrowsing = false;
if (FrameView* frameView = view->frameView()) {
LocalFrame& frame = frameView->frame();
caretBrowsing = frame.settings() && frame.settings()->caretBrowsingEnabled();
}
return (caretBrowsing || isContentEditable);
}
void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged)
{
m_caretRectNeedsUpdate = true;
if (caretRectChanged)
return;
if (RenderView* view = node->document().renderView()) {
if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
repaintCaretForLocalRect(node, localCaretRectWithoutUpdate());
}
}
void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
{
if (m_caretVisibility == Hidden)
return;
LayoutRect drawingRect = localCaretRectWithoutUpdate();
RenderObject* renderer = caretRenderer(node);
if (renderer && renderer->isBox())
toRenderBox(renderer)->flipForWritingMode(drawingRect);
drawingRect.moveBy(roundedIntPoint(paintOffset));
LayoutRect caret = intersection(drawingRect, clipRect);
if (caret.isEmpty())
return;
Color caretColor = Color::black;
Element* element;
if (node->isElementNode())
element = toElement(node);
else
element = node->parentElement();
if (element && element->renderer())
caretColor = element->renderer()->resolveColor(CSSPropertyColor);
context->fillRect(caret, caretColor);
}
void DragCaretController::paintDragCaret(LocalFrame* frame, GraphicsContext* p, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
{
if (m_position.deepEquivalent().deprecatedNode()->document().frame() == frame)
paintCaret(m_position.deepEquivalent().deprecatedNode(), p, paintOffset, clipRect);
}
}