+2004-11-22 David Hyatt <hyatt@apple.com>
+
+ Fix for 3673381, huge directory listing so slow it seems like a hang. Rework painting and hit testing so that
+ it crawls the line box tree instead of the render tree. This allows more precise intersection/containment testing
+ that lets us short circuit earlier when painting and hit testing.
+
+ Reviewed by mjs
+
+ * khtml/khtml_part.cpp:
+ (KHTMLPart::isPointInsideSelection):
+ * khtml/rendering/render_block.cpp:
+ (khtml::RenderBlock::paint):
+ (khtml::RenderBlock::paintChildren):
+ (khtml::RenderBlock::paintObject):
+ (khtml::RenderBlock::paintFloats):
+ (khtml::RenderBlock::nodeAtPoint):
+ * khtml/rendering/render_block.h:
+ * khtml/rendering/render_box.cpp:
+ (RenderBox::nodeAtPoint):
+ * khtml/rendering/render_box.h:
+ * khtml/rendering/render_br.h:
+ * khtml/rendering/render_canvas.cpp:
+ (RenderCanvas::paint):
+ * khtml/rendering/render_flow.cpp:
+ (RenderFlow::paintLines):
+ (RenderFlow::hitTestLines):
+ (RenderFlow::caretRect):
+ (RenderFlow::addFocusRingRects):
+ (RenderFlow::paintFocusRing):
+ (RenderFlow::paintOutlines):
+ (RenderFlow::paintOutlineForLine):
+ * khtml/rendering/render_flow.h:
+ * khtml/rendering/render_frames.cpp:
+ (RenderFrameSet::nodeAtPoint):
+ * khtml/rendering/render_frames.h:
+ * khtml/rendering/render_image.cpp:
+ (RenderImage::nodeAtPoint):
+ * khtml/rendering/render_image.h:
+ * khtml/rendering/render_inline.cpp:
+ (RenderInline::paint):
+ (RenderInline::nodeAtPoint):
+ * khtml/rendering/render_inline.h:
+ * khtml/rendering/render_layer.cpp:
+ (RenderLayer::paintLayer):
+ (RenderLayer::hitTest):
+ (RenderLayer::hitTestLayer):
+ * khtml/rendering/render_layer.h:
+ * khtml/rendering/render_line.cpp:
+ (khtml::InlineBox::paint):
+ (khtml::InlineBox::nodeAtPoint):
+ (khtml::InlineFlowBox::flowObject):
+ (khtml::InlineFlowBox::nodeAtPoint):
+ (khtml::InlineFlowBox::paint):
+ (khtml::InlineFlowBox::paintBackgrounds):
+ (khtml::InlineFlowBox::paintBackground):
+ (khtml::InlineFlowBox::paintBackgroundAndBorder):
+ (khtml::InlineFlowBox::paintDecorations):
+ (khtml::EllipsisBox::paint):
+ (khtml::EllipsisBox::nodeAtPoint):
+ (khtml::RootInlineBox::paintEllipsisBox):
+ (khtml::RootInlineBox::paint):
+ (khtml::RootInlineBox::nodeAtPoint):
+ * khtml/rendering/render_line.h:
+ (khtml::InlineRunBox::paintBackgroundAndBorder):
+ * khtml/rendering/render_object.cpp:
+ (RenderObject::hitTest):
+ (RenderObject::setInnerNode):
+ (RenderObject::nodeAtPoint):
+ * khtml/rendering/render_object.h:
+ (khtml::RenderObject::PaintInfo::PaintInfo):
+ (khtml::RenderObject::PaintInfo::~PaintInfo):
+ (khtml::RenderObject::paintingRootForChildren):
+ (khtml::RenderObject::shouldPaintWithinRoot):
+ * khtml/rendering/render_table.cpp:
+ (RenderTable::layout):
+ (RenderTable::paint):
+ * khtml/rendering/render_text.cpp:
+ (simpleDifferenceBetweenColors):
+ (correctedTextColor):
+ (InlineTextBox::nodeAtPoint):
+ (InlineTextBox::paint):
+ (InlineTextBox::selectionStartEnd):
+ (InlineTextBox::paintSelection):
+ (InlineTextBox::paintMarkedTextBackground):
+ (InlineTextBox::paintDecoration):
+ (RenderText::posOfChar):
+ * khtml/rendering/render_text.h:
+ (khtml::RenderText::paint):
+ (khtml::RenderText::layout):
+ (khtml::RenderText::nodeAtPoint):
+ * khtml/xml/dom2_eventsimpl.cpp:
+ (MouseEventImpl::computeLayerPos):
+ * khtml/xml/dom_docimpl.cpp:
+ (DocumentImpl::prepareMouseEvent):
+ * kwq/KWQAccObject.mm:
+ (-[KWQAccObject accessibilityHitTest:]):
+ * kwq/KWQKHTMLPart.mm:
+ (KWQKHTMLPart::scrollOverflowWithScrollWheelEvent):
+ (KWQKHTMLPart::eventMayStartDrag):
+ (KWQKHTMLPart::khtmlMouseMoveEvent):
+ * kwq/WebCoreBridge.mm:
+ (-[WebCoreBridge elementAtPoint:]):
+ (-[WebCoreBridge _positionForPoint:]):
+
2004-11-22 Maciej Stachowiak <mjs@apple.com>
Reviewed by Dave.
return false;
RenderObject::NodeInfo nodeInfo(true, true);
- xmlDocImpl()->renderer()->layer()->nodeAtPoint(nodeInfo, x, y);
+ xmlDocImpl()->renderer()->layer()->hitTest(nodeInfo, x, y);
NodeImpl *innerNode = nodeInfo.innerNode();
if (!innerNode || !innerNode->renderer())
return false;
_tx += m_x;
_ty += m_y;
- // check if we need to do anything at all...
- if (!isRoot() && !isInlineFlow() && !isRelPositioned() && !isPositioned()) {
+ // Check if we need to do anything at all.
+ // FIXME: This check is limited to only the y-coordinates when it could check x as well.
+ // Compacts keep us from being strict about x-direction at the moment.
+ if (!isInlineFlow() && !isRoot()) {
int h = m_overflowHeight;
int yPos = _ty;
if (m_floatingObjects && floatBottom() > h)
h = floatBottom();
- // Sanity check the first line
+ // FIXME: This is a pretty feeble check that doesn't really work in practice, since top overflow
+ // is not propagated. Sanity check the first line
// to see if it extended a little above our box. Overflow out the bottom is already handled via
// overflowHeight(), so we don't need to check that.
if (m_firstLineBox && m_firstLineBox->topOverflow() < 0)
return;
}
- return RenderBlock::paintObject(i, _tx, _ty);
+ return paintObject(i, _tx, _ty);
}
-void RenderBlock::paintObject(PaintInfo& i, int _tx, int _ty)
+void RenderBlock::paintChildren(PaintInfo& i, int _tx, int _ty)
{
- PaintAction paintAction = i.phase;
-
- // If we're a repositioned run-in, don't paint background/borders.
- bool inlineFlow = isInlineFlow();
- bool isPrinting = (i.p->device()->devType() == QInternal::Printer);
-
- // 1. paint background, borders etc
- if (!inlineFlow &&
- (paintAction == PaintActionElementBackground || paintAction == PaintActionChildBackground) &&
- shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) {
- paintBoxDecorations(i, _tx, _ty);
- }
-
- // We're done. We don't bother painting any children.
- if (paintAction == PaintActionElementBackground)
- return;
// We don't paint our own background, but we do let the kids paint their backgrounds.
- if (paintAction == PaintActionChildBackgrounds)
- paintAction = PaintActionChildBackground;
- PaintInfo paintInfo(i.p, i.r, paintAction, paintingRootForChildren(i));
-
- paintLineBoxBackgroundBorder(paintInfo, _tx, _ty);
+ PaintInfo paintInfo(i.p, i.r, i.phase == PaintActionChildBlockBackgrounds ? PaintActionChildBlockBackground : i.phase,
+ paintingRootForChildren(i));
+ bool isPrinting = (i.p->device()->devType() == QInternal::Printer);
- // 2. paint contents
- int scrolledX = _tx;
- int scrolledY = _ty;
- if (hasOverflowClip())
- m_layer->subtractScrollOffset(scrolledX, scrolledY);
-
- paintLineBoxDecorations(paintInfo, scrolledX, scrolledY); // Underline/overline
for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
// Check for page-break-before: always, and if it's set, break and bail.
if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS &&
}
if (!child->layer() && !child->isFloating())
- child->paint(paintInfo, scrolledX, scrolledY);
+ child->paint(paintInfo, _tx, _ty);
// Check for page-break-after: always, and if it's set, break and bail.
if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS &&
return;
}
}
- paintLineBoxDecorations(paintInfo, scrolledX, scrolledY, true); // Strike-through
- if (!inlineFlow) {
- paintEllipsisBoxes(paintInfo, scrolledX, scrolledY); // Text overflow ellipsis (...)
- paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
+}
+
+void RenderBlock::paintObject(PaintInfo& i, int _tx, int _ty)
+{
+ PaintAction paintAction = i.phase;
+
+ // If we're a repositioned run-in or a compact, don't paint background/borders.
+ bool inlineFlow = isInlineFlow();
+
+ // 1. paint background, borders etc
+ if (!inlineFlow &&
+ (paintAction == PaintActionBlockBackground || paintAction == PaintActionChildBlockBackground) &&
+ shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) {
+ paintBoxDecorations(i, _tx, _ty);
}
- // 3. paint floats.
+ // We're done. We don't bother painting any children.
+ if (paintAction == PaintActionBlockBackground)
+ return;
+
+ // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s
+ int scrolledX = _tx;
+ int scrolledY = _ty;
+ if (hasOverflowClip())
+ m_layer->subtractScrollOffset(scrolledX, scrolledY);
+
+ // 2. paint contents
+ if (childrenInline())
+ paintLines(i, scrolledX, scrolledY);
+ else
+ paintChildren(i, scrolledX, scrolledY);
+
+ // 3. paint selection
+ if (!inlineFlow)
+ paintSelection(i, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
+
+ // 4. paint floats.
if (!inlineFlow && (paintAction == PaintActionFloat || paintAction == PaintActionSelection))
- paintFloats(paintInfo, scrolledX, scrolledY, paintAction == PaintActionSelection);
+ paintFloats(i, scrolledX, scrolledY, paintAction == PaintActionSelection);
- // 4. paint outline.
+ // 5. paint outline.
if (!inlineFlow && paintAction == PaintActionOutline &&
style()->outlineWidth() && style()->visibility() == VISIBLE)
paintOutline(i.p, _tx, _ty, width(), height(), style());
- // 5. paint caret.
- /*
- If the caret's node's render object's containing block is this block,
- and the paint action is PaintActionForeground,
- then paint the caret.
- */
- if (paintAction == PaintActionForeground) {
+ // 6. paint caret.
+ // If the caret's node's render object's containing block is this block, and the paint action is PaintActionForeground,
+ // then paint the caret.
+ if (!inlineFlow && paintAction == PaintActionForeground) {
const Selection &s = document()->part()->selection();
NodeImpl *caretNode = s.start().node();
RenderObject *renderer = caretNode ? caretNode->renderer() : 0;
for ( ; (r = it.current()); ++it) {
// Only paint the object if our noPaint flag isn't set.
if (!r->noPaint && !r->node->layer()) {
- PaintInfo info(i.p, i.r, paintSelection ? PaintActionSelection : PaintActionElementBackground, i.paintingRoot);
+ PaintInfo info(i.p, i.r, paintSelection ? PaintActionSelection : PaintActionBlockBackground, i.paintingRoot);
int tx = _tx + r->left - r->node->xPos() + r->node->marginLeft();
int ty = _ty + r->startY - r->node->yPos() + r->node->marginTop();
r->node->paint(info, tx, ty);
if (!paintSelection) {
- info.phase = PaintActionChildBackgrounds;
+ info.phase = PaintActionChildBlockBackgrounds;
r->node->paint(info, tx, ty);
info.phase = PaintActionFloat;
r->node->paint(info, tx, ty);
}
bool RenderBlock::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inBox)
+ HitTestAction hitTestAction)
{
- bool inScrollbar = isPointInScrollbar(_x, _y, _tx+xPos(), _ty+yPos());
- if (inScrollbar && hitTestAction != HitTestChildrenOnly)
- inBox = true;
+ bool inlineFlow = isInlineFlow();
+
+ int tx = _tx + xPos();
+ int ty = _ty + yPos();
+
+ if (!inlineFlow && !isRoot()) {
+ // Check if we need to do anything at all with this block.
+ // FIXME: This check is limited to only the y-coordinates when it could check x as well.
+ // Compacts keep us from being strict about x-coordinates at the moment.
+ int h = m_overflowHeight;
+ if (m_floatingObjects && floatBottom() > h)
+ h = floatBottom();
+ if (isTableCell())
+ h = kMax(height() + borderTopExtra() + borderBottomExtra(), h);
+ if ((ty > _y) || (ty + h <= _y))
+ return false;
+ }
- if (hitTestAction != HitTestSelfOnly && !inScrollbar) {
- int stx = _tx + xPos();
- int sty = _ty + yPos();
-
- if (m_floatingObjects) {
- if (hasOverflowClip())
- m_layer->subtractScrollOffset(stx, sty);
- if (isCanvas()) {
- stx += static_cast<RenderCanvas*>(this)->view()->contentsX();
- sty += static_cast<RenderCanvas*>(this)->view()->contentsY();
- }
- FloatingObject* o;
- QPtrListIterator<FloatingObject> it(*m_floatingObjects);
- for (it.toLast(); (o = it.current()); --it)
- if (!o->noPaint && !o->node->layer())
- inBox |= o->node->nodeAtPoint(info, _x, _y,
- stx+o->left + o->node->marginLeft() - o->node->xPos(),
- sty+o->startY + o->node->marginTop() - o->node->yPos());
+ if (isTableCell())
+ ty += borderTopExtra();
+
+ // See if we're inside the scrollbar (if we're overflow:scroll/auto).
+ if (isPointInScrollbar(_x, _y, tx, ty)) {
+ if (hitTestAction == HitTestBlockBackground) {
+ setInnerNode(info);
+ return true;
}
+ return false;
+ }
- if (hasMarkupTruncation()) {
- for (RootInlineBox* box = lastRootBox(); box; box = box->prevRootBox()) {
- if (box->ellipsisBox()) {
- inBox |= box->hitTestEllipsisBox(info, _x, _y, stx, sty, hitTestAction, inBox);
- break;
- }
+ // Hit test descendants first.
+ int scrolledX = tx;
+ int scrolledY = ty;
+ if (hasOverflowClip())
+ m_layer->subtractScrollOffset(scrolledX, scrolledY);
+ if (childrenInline() && !isTable()) {
+ // We have to hit-test our line boxes.
+ if (hitTestLines(info, _x, _y, scrolledX, scrolledY, hitTestAction)) {
+ setInnerNode(info);
+ return true;
+ }
+ }
+ else {
+ // Hit test our children.
+ HitTestAction childHitTest = hitTestAction;
+ if (hitTestAction == HitTestChildBlockBackgrounds)
+ childHitTest = HitTestChildBlockBackground;
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling())
+ if (!child->layer() && !child->isFloating() && child->nodeAtPoint(info, _x, _y, scrolledX, scrolledY, childHitTest)) {
+ setInnerNode(info);
+ return true;
+ }
+ }
+
+ // Hit test floats.
+ if (hitTestAction == HitTestFloat && m_floatingObjects) {
+ if (isCanvas()) {
+ scrolledX += static_cast<RenderCanvas*>(this)->view()->contentsX();
+ scrolledY += static_cast<RenderCanvas*>(this)->view()->contentsY();
+ }
+
+ FloatingObject* o;
+ QPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for (it.toLast(); (o = it.current()); --it)
+ if (!o->noPaint && !o->node->layer() && o->node->hitTest(info, _x, _y,
+ scrolledX + o->left + o->node->marginLeft() - o->node->xPos(),
+ scrolledY + o->startY + o->node->marginTop() - o->node->yPos())) {
+ setInnerNode(info);
+ return true;
}
+ }
+
+ // Now hit test our background.
+ if (!inlineFlow && (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)) {
+ QRect boundsRect(tx, ty, m_width, m_height);
+ if (isRoot() || (style()->visibility() == VISIBLE && boundsRect.contains(_x, _y))) {
+ setInnerNode(info);
+ return true;
}
}
- inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
- return inBox;
+ return false;
}
Position RenderBlock::positionForBox(InlineBox *box, bool start) const
virtual void paint(PaintInfo& i, int tx, int ty);
void paintObject(PaintInfo& i, int tx, int ty);
void paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelection = false);
+ void paintChildren(PaintInfo& i, int _tx, int _ty);
void paintEllipsisBoxes(PaintInfo& i, int _tx, int _ty);
void paintSelection(PaintInfo& i, int _tx, int _ty);
int leftOffset(int y) const { return leftRelOffset(y, leftOffset(), true); }
virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
+ HitTestAction hitTestAction);
bool isPointInScrollbar(int x, int y, int tx, int ty);
return m_height;
}
+// Hit Testing
+bool RenderBox::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+ HitTestAction hitTestAction)
+{
+ // Check kids first.
+ _tx += m_x;
+ _ty += m_y;
+ for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
+ if (child->nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction)) {
+ setInnerNode(info);
+ return true;
+ }
+ }
+
+ // Check our bounds next. For this purpose always assume that we can only be hit in the
+ // foreground phase (which is true for replaced elements like images).
+ if (hitTestAction != HitTestForeground)
+ return false;
+
+ QRect boundsRect(_tx, _ty, m_width, m_height);
+ if (boundsRect.contains(_x, _y)) {
+ setInnerNode(info);
+ return true;
+ }
+ return false;
+}
// --------------------- painting stuff -------------------------------
virtual void setStyle(RenderStyle *style);
virtual void paint(PaintInfo& i, int _tx, int _ty);
+ virtual bool nodeAtPoint(NodeInfo& i, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction);
virtual void detach();
virtual QRect selectionRect() { return QRect(); }
- virtual void paint(PaintInfo& i, int tx, int ty) {};
-
virtual unsigned int width(unsigned int, unsigned int, const Font *) const { return 0; }
virtual unsigned int width( unsigned int, unsigned int, bool) const { return 0; }
kdDebug( 6040 ) << renderName() << "(RenderCanvas) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl;
#endif
// 1. paint background, borders etc
- if (i.phase == PaintActionElementBackground) {
+ if (i.phase == PaintActionBlockBackground) {
paintBoxDecorations(i, _tx, _ty);
return;
}
return flowBox;
}
-void RenderFlow::paintLineBoxBackgroundBorder(PaintInfo& i, int _tx, int _ty)
+void RenderFlow::paintLines(PaintInfo& i, int _tx, int _ty)
{
- if (!shouldPaintWithinRoot(i))
+ // Only paint during the foreground/selection phases.
+ if (i.phase != PaintActionForeground && i.phase != PaintActionSelection && i.phase != PaintActionOutline)
return;
+ bool inlineFlow = isInlineFlow();
+ if (inlineFlow)
+ KHTMLAssert(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
+
+ // If we have no lines then we have no work to do.
if (!firstLineBox())
return;
-
- if (style()->visibility() == VISIBLE && i.phase == PaintActionForeground) {
- // We can check the first box and last box and avoid painting if we don't
- // intersect.
- int yPos = _ty + firstLineBox()->yPos();
- int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
- if( (yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y()))
- return;
-
- // See if our boxes intersect with the dirty rect. If so, then we paint
- // them. Note that boxes can easily overlap, so we can't make any assumptions
- // based off positions of our first line box or our last line box.
- int xOffsetWithinLineBoxes = 0;
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- yPos = _ty + curr->yPos();
- h = curr->height();
- if ((yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y()))
- curr->paintBackgroundAndBorder(i, _tx, _ty, xOffsetWithinLineBoxes);
- xOffsetWithinLineBoxes += curr->width();
+
+ // We can check the first box and last box and avoid painting if we don't
+ // intersect. This is a quick short-circuit that we can take to avoid walking any lines.
+ // FIXME: This check is flawed in two extremely obscure ways.
+ // (1) If some line in the middle has a huge overflow, it might actually extend below the last line.
+ // (2) The overflow from an inline block on a line is not reported to the line.
+ int yPos = firstLineBox()->root()->selectionTop() - maximalOutlineSize(i.phase);
+ int h = maximalOutlineSize(i.phase) + lastLineBox()->root()->selectionTop() + lastLineBox()->root()->selectionHeight() - yPos;
+ yPos += _ty;
+ if ((yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y()))
+ return;
+
+ // See if our root lines intersect with the dirty rect. If so, then we paint
+ // them. Note that boxes can easily overlap, so we can't make any assumptions
+ // based off positions of our first line box or our last line box.
+ bool isPrinting = (i.p->device()->devType() == QInternal::Printer);
+ for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) {
+ if (isPrinting) {
+ // FIXME: This is a feeble effort to avoid splitting a line across two pages.
+ // It is utterly inadequate, and this should not be done at paint time at all.
+ // The whole way objects break across pages needs to be redone.
+ if (_ty + curr->root()->bottomOverflow() > i.r.y() + i.r.height()) {
+ RenderCanvas* canvasObj = canvas();
+ if (_ty + curr->root()->topOverflow() < canvasObj->truncatedAt())
+ canvasObj->setBestTruncatedAt(_ty + curr->root()->topOverflow(), this);
+ // Let's stop here.
+ break;
+ }
+ }
+
+ yPos = _ty + curr->root()->selectionTop() - maximalOutlineSize(i.phase);
+ h = curr->root()->selectionHeight() + 2 * maximalOutlineSize(i.phase);
+ if ((yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y()))
+ curr->paint(i, _tx, _ty);
+ }
+
+ if (i.phase == PaintActionOutline && i.outlineObjects) {
+ // FIXME: Will the order in which we added objects to the dictionary be preserved? Probably not.
+ // This means the paint order of outlines will be wrong, although this is a minor issue.
+ QPtrDictIterator<RenderFlow> objects(*i.outlineObjects);
+ for (objects.toFirst(); objects.current(); ++objects) {
+#ifdef APPLE_CHANGES
+ if (objects.current()->style()->outlineStyleIsAuto())
+ objects.current()->paintFocusRing(i.p, _tx, _ty);
+ else
+#endif
+ objects.current()->paintOutlines(i.p, _tx, _ty);
}
}
}
-void RenderFlow::paintLineBoxDecorations(PaintInfo& i, int _tx, int _ty, bool paintedChildren)
+bool RenderFlow::hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction)
{
- if (!shouldPaintWithinRoot(i))
- return;
+ if (hitTestAction != HitTestForeground)
+ return false;
- // We only paint line box decorations in strict or almost strict mode.
- // Otherwise we let the InlineTextBoxes paint their own decorations.
- if (style()->htmlHacks() || !firstLineBox())
- return;
+ bool inlineFlow = isInlineFlow();
+ if (inlineFlow)
+ KHTMLAssert(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
- if (style()->visibility() == VISIBLE && i.phase == PaintActionForeground) {
- // We can check the first box and last box and avoid painting if we don't
- // intersect.
- int yPos = _ty + firstLineBox()->yPos();;
- int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
- if( (yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y()))
- return;
-
- // See if our boxes intersect with the dirty rect. If so, then we paint
- // them. Note that boxes can easily overlap, so we can't make any assumptions
- // based off positions of our first line box or our last line box.
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- yPos = _ty + curr->yPos();
- h = curr->height();
- if ((yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y()))
- curr->paintDecorations(i, _tx, _ty, paintedChildren);
+ // If we have no lines then we have no work to do.
+ if (!firstLineBox())
+ return false;
+
+ // We can check the first box and last box and avoid hit testing if we don't
+ // contain the point. This is a quick short-circuit that we can take to avoid walking any lines.
+ // FIXME: This check is flawed in two extremely obscure ways.
+ // (1) If some line in the middle has a huge overflow, it might actually extend below the last line.
+ // (2) The overflow from an inline block on a line is not reported to the line.
+ if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow()))
+ return false;
+
+ // See if our root lines contain the point. If so, then we hit test
+ // them further. Note that boxes can easily overlap, so we can't make any assumptions
+ // based off positions of our first line box or our last line box.
+ for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) {
+ if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) {
+ bool inside = curr->nodeAtPoint(i, x, y, tx, ty);
+ if (inside) {
+ setInnerNode(i);
+ return true;
+ }
}
}
+
+ return false;
}
QRect RenderFlow::getAbsoluteRepaintRect()
return QRect(_x, _y, width, height);
}
+
+#if APPLE_CHANGES
+void RenderFlow::addFocusRingRects(QPainter *p, int _tx, int _ty)
+{
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ p->addFocusRingRect(_tx + curr->xPos(),
+ _ty + curr->yPos(),
+ curr->width(),
+ curr->height());
+ }
+
+ for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
+ if (!curr->isText())
+ curr->addFocusRingRects(p, _tx + curr->xPos(), _ty + curr->yPos());
+ }
+
+ if (continuation())
+ continuation()->addFocusRingRects(p,
+ _tx - containingBlock()->xPos() + continuation()->xPos(),
+ _ty - containingBlock()->yPos() + continuation()->yPos());
+}
+
+void RenderFlow::paintFocusRing(QPainter *p, int tx, int ty)
+{
+ int ow = style()->outlineWidth();
+ QColor oc = style()->outlineColor();
+ if (!oc.isValid())
+ oc = style()->color();
+
+ p->initFocusRing(ow, style()->outlineOffset(), oc);
+ addFocusRingRects(p, tx, ty);
+ p->drawFocusRing();
+ p->clearFocusRing();
+}
+#endif
+
+void RenderFlow::paintOutlines(QPainter *p, int _tx, int _ty)
+{
+ if (style()->outlineStyle() <= BHIDDEN)
+ return;
+
+ QPtrList <QRect> rects;
+ rects.setAutoDelete(true);
+
+ rects.append(new QRect(0,0,0,0));
+ for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
+ rects.append(new QRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
+ }
+ rects.append(new QRect(0,0,0,0));
+
+ for (unsigned int i = 1; i < rects.count() - 1; i++)
+ paintOutlineForLine(p, _tx, _ty, *rects.at(i-1), *rects.at(i), *rects.at(i+1));
+}
+
+void RenderFlow::paintOutlineForLine(QPainter *p, int tx, int ty, const QRect &lastline, const QRect &thisline, const QRect &nextline)
+{
+ int ow = style()->outlineWidth();
+ EBorderStyle os = style()->outlineStyle();
+ QColor oc = style()->outlineColor();
+ if (!oc.isValid())
+ oc = style()->color();
+
+ int offset = style()->outlineOffset();
+
+ int t = ty + thisline.top() - offset;
+ int l = tx + thisline.left() - offset;
+ int b = ty + thisline.bottom() + offset + 1;
+ int r = tx + thisline.right() + offset + 1;
+
+ // left edge
+ drawBorder(p,
+ l - ow,
+ t - (lastline.isEmpty() || thisline.left() < lastline.left() || lastline.right() <= thisline.left() ? ow : 0),
+ l,
+ b + (nextline.isEmpty() || thisline.left() <= nextline.left() || nextline.right() <= thisline.left() ? ow : 0),
+ BSLeft,
+ oc, style()->color(), os,
+ (lastline.isEmpty() || thisline.left() < lastline.left() || lastline.right() <= thisline.left() ? ow : -ow),
+ (nextline.isEmpty() || thisline.left() <= nextline.left() || nextline.right() <= thisline.left() ? ow : -ow),
+ true);
+
+ // right edge
+ drawBorder(p,
+ r,
+ t - (lastline.isEmpty() || lastline.right() < thisline.right() || thisline.right() <= lastline.left() ? ow : 0),
+ r + ow,
+ b + (nextline.isEmpty() || nextline.right() <= thisline.right() || thisline.right() <= nextline.left() ? ow : 0),
+ BSRight,
+ oc, style()->color(), os,
+ (lastline.isEmpty() || lastline.right() < thisline.right() || thisline.right() <= lastline.left() ? ow : -ow),
+ (nextline.isEmpty() || nextline.right() <= thisline.right() || thisline.right() <= nextline.left() ? ow : -ow),
+ true);
+ // upper edge
+ if ( thisline.left() < lastline.left())
+ drawBorder(p,
+ l - ow,
+ t - ow,
+ QMIN(r+ow, (lastline.isValid()? tx+lastline.left() : 1000000)),
+ t ,
+ BSTop, oc, style()->color(), os,
+ ow,
+ (lastline.isValid() && tx+lastline.left()+1<r+ow ? -ow : ow),
+ true);
+
+ if (lastline.right() < thisline.right())
+ drawBorder(p,
+ QMAX(lastline.isValid()?tx + lastline.right() + 1:-1000000, l - ow),
+ t - ow,
+ r + ow,
+ t ,
+ BSTop, oc, style()->color(), os,
+ (lastline.isValid() && l-ow < tx+lastline.right()+1 ? -ow : ow),
+ ow,
+ true);
+
+ // lower edge
+ if ( thisline.left() < nextline.left())
+ drawBorder(p,
+ l - ow,
+ b,
+ QMIN(r+ow, nextline.isValid()? tx+nextline.left()+1 : 1000000),
+ b + ow,
+ BSBottom, oc, style()->color(), os,
+ ow,
+ (nextline.isValid() && tx+nextline.left()+1<r+ow? -ow : ow),
+ true);
+
+ if (nextline.right() < thisline.right())
+ drawBorder(p,
+ QMAX(nextline.isValid()?tx+nextline.right()+1:-1000000 , l-ow),
+ b,
+ r + ow,
+ b + ow,
+ BSBottom, oc, style()->color(), os,
+ (nextline.isValid() && l-ow < tx+nextline.right()+1? -ow : ow),
+ ow,
+ true);
+}
virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun=false);
virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox = false);
- void paintLineBoxBackgroundBorder(PaintInfo& i, int _tx, int _ty);
- void paintLineBoxDecorations(PaintInfo& i, int _tx, int _ty, bool paintedChildren = false);
+ void paintLines(PaintInfo& i, int _tx, int _ty);
+ bool hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction);
virtual QRect getAbsoluteRepaintRect();
virtual QRect caretRect(int offset, EAffinity affinity = UPSTREAM, int *extraWidthToEndOfLine = 0);
+#ifdef APPLE_CHANGES
+ virtual void addFocusRingRects(QPainter *painter, int _tx, int _ty);
+ void paintFocusRing(QPainter *p, int tx, int ty);
+#endif
+ void paintOutlineForLine(QPainter *p, int tx, int ty, const QRect &prevLine, const QRect &thisLine, const QRect &nextLine);
+ void paintOutlines(QPainter *p, int tx, int ty);
+
protected:
// An inline can be split with blocks occurring in between the inline content.
// When this occurs we need a pointer to our next object. We can basically be
}
bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inside)
+ HitTestAction hitTestAction)
{
- RenderContainer::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside);
+ if (hitTestAction != HitTestForeground)
+ return false;
- inside = m_resizing || canResize(_x, _y);
-
- if ( inside && element() && !element()->noResize() && !info.readonly()){
+ bool inside = RenderContainer::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction) ||
+ m_resizing || canResize(_x, _y);
+ if (inside && element() && !element()->noResize() && !info.readonly()){
info.setInnerNode(element());
info.setInnerNonSharedNode(element());
}
void setResizing(bool e);
bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
+ HitTestAction hitTestAction);
DOM::HTMLFrameSetElementImpl *element() const
{ return static_cast<DOM::HTMLFrameSetElementImpl*>(RenderObject::element()); }
}
bool RenderImage::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inside)
+ HitTestAction hitTestAction)
{
- inside |= RenderReplaced::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside);
+ bool inside = RenderReplaced::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction);
if (inside && element()) {
int tx = _tx + m_x;
CachedImage* getImage() const { return image; }
virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
+ HitTestAction hitTestAction);
virtual int calcReplacedWidth() const;
virtual int calcReplacedHeight() const;
void RenderInline::paint(PaintInfo& i, int _tx, int _ty)
{
-#ifdef DEBUG_LAYOUT
- // kdDebug( 6040 ) << renderName() << "(RenderInline) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl;
-#endif
-
- // We're done. We don't bother painting any children.
- if (i.phase == PaintActionElementBackground)
- return;
-
- // We don't paint our own background, but we do let the kids paint their backgrounds.
- PaintInfo paintInfo(i.p, i.r, i.phase, paintingRootForChildren(i));
- if (i.phase == PaintActionChildBackgrounds)
- paintInfo.phase = PaintActionChildBackground;
-
- paintLineBoxBackgroundBorder(paintInfo, _tx, _ty);
-
- paintLineBoxDecorations(paintInfo, _tx, _ty); // Underline/overline
-
- for (RenderObject *child = firstChild(); child; child = child->nextSibling())
- if(!child->layer() && !child->isFloating())
- child->paint(paintInfo, _tx, _ty);
-
- paintLineBoxDecorations(paintInfo, _tx, _ty, true); // Strike-through
-
- if (style()->visibility() == VISIBLE && paintInfo.phase == PaintActionOutline) {
-#if APPLE_CHANGES
- if (style()->outlineStyleIsAuto())
- paintFocusRing(paintInfo.p, _tx, _ty);
- else
-#endif
- paintOutlines(paintInfo.p, _tx, _ty);
- }
+ paintLines(i, _tx, _ty);
}
void RenderInline::absoluteRects(QValueList<QRect>& rects, int _tx, int _ty)
_ty - containingBlock()->yPos() + continuation()->yPos());
}
-#if APPLE_CHANGES
-void RenderInline::addFocusRingRects(QPainter *p, int _tx, int _ty)
-{
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- p->addFocusRingRect(_tx + curr->xPos(),
- _ty + curr->yPos(),
- curr->width(),
- curr->height());
- }
-
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (!curr->isText())
- curr->addFocusRingRects(p, _tx + curr->xPos(), _ty + curr->yPos());
- }
-
- if (continuation())
- continuation()->addFocusRingRects(p,
- _tx - containingBlock()->xPos() + continuation()->xPos(),
- _ty - containingBlock()->yPos() + continuation()->yPos());
-}
-
-void RenderInline::paintFocusRing(QPainter *p, int tx, int ty)
-{
- int ow = style()->outlineWidth();
- if (ow == 0 || m_isContinuation) // Continuations get painted by the original inline.
- return;
-
- QColor oc = style()->outlineColor();
- if (!oc.isValid())
- oc = style()->color();
-
- p->initFocusRing(ow, style()->outlineOffset(), oc);
- addFocusRingRects(p, tx, ty);
- p->drawFocusRing();
- p->clearFocusRing();
-}
-#endif
-
-void RenderInline::paintOutlines(QPainter *p, int _tx, int _ty)
-{
- if (style()->outlineWidth() == 0 || style()->outlineStyle() <= BHIDDEN)
- return;
-
- QPtrList <QRect> rects;
- rects.setAutoDelete(true);
-
- rects.append(new QRect(0,0,0,0));
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- rects.append(new QRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
- }
- rects.append(new QRect(0,0,0,0));
-
- for (unsigned int i = 1; i < rects.count() - 1; i++)
- paintOutline(p, _tx, _ty, *rects.at(i-1), *rects.at(i), *rects.at(i+1));
-}
-
-void RenderInline::paintOutline(QPainter *p, int tx, int ty, const QRect &lastline, const QRect &thisline, const QRect &nextline)
-{
- int ow = style()->outlineWidth();
- if (ow == 0 || m_isContinuation) // Continuations get painted by the original inline.
- return;
-
- EBorderStyle os = style()->outlineStyle();
- QColor oc = style()->outlineColor();
- if (!oc.isValid())
- oc = style()->color();
-
- int offset = style()->outlineOffset();
-
- int t = ty + thisline.top() - offset;
- int l = tx + thisline.left() - offset;
- int b = ty + thisline.bottom() + offset + 1;
- int r = tx + thisline.right() + offset + 1;
-
- // left edge
- drawBorder(p,
- l - ow,
- t - (lastline.isEmpty() || thisline.left() < lastline.left() || lastline.right() <= thisline.left() ? ow : 0),
- l,
- b + (nextline.isEmpty() || thisline.left() <= nextline.left() || nextline.right() <= thisline.left() ? ow : 0),
- BSLeft,
- oc, style()->color(), os,
- (lastline.isEmpty() || thisline.left() < lastline.left() || lastline.right() <= thisline.left() ? ow : -ow),
- (nextline.isEmpty() || thisline.left() <= nextline.left() || nextline.right() <= thisline.left() ? ow : -ow),
- true);
-
- // right edge
- drawBorder(p,
- r,
- t - (lastline.isEmpty() || lastline.right() < thisline.right() || thisline.right() <= lastline.left() ? ow : 0),
- r + ow,
- b + (nextline.isEmpty() || nextline.right() <= thisline.right() || thisline.right() <= nextline.left() ? ow : 0),
- BSRight,
- oc, style()->color(), os,
- (lastline.isEmpty() || lastline.right() < thisline.right() || thisline.right() <= lastline.left() ? ow : -ow),
- (nextline.isEmpty() || nextline.right() <= thisline.right() || thisline.right() <= nextline.left() ? ow : -ow),
- true);
- // upper edge
- if ( thisline.left() < lastline.left())
- drawBorder(p,
- l - ow,
- t - ow,
- QMIN(r+ow, (lastline.isValid()? tx+lastline.left() : 1000000)),
- t ,
- BSTop, oc, style()->color(), os,
- ow,
- (lastline.isValid() && tx+lastline.left()+1<r+ow ? -ow : ow),
- true);
-
- if (lastline.right() < thisline.right())
- drawBorder(p,
- QMAX(lastline.isValid()?tx + lastline.right() + 1:-1000000, l - ow),
- t - ow,
- r + ow,
- t ,
- BSTop, oc, style()->color(), os,
- (lastline.isValid() && l-ow < tx+lastline.right()+1 ? -ow : ow),
- ow,
- true);
-
- // lower edge
- if ( thisline.left() < nextline.left())
- drawBorder(p,
- l - ow,
- b,
- QMIN(r+ow, nextline.isValid()? tx+nextline.left()+1 : 1000000),
- b + ow,
- BSBottom, oc, style()->color(), os,
- ow,
- (nextline.isValid() && tx+nextline.left()+1<r+ow? -ow : ow),
- true);
-
- if (nextline.right() < thisline.right())
- drawBorder(p,
- QMAX(nextline.isValid()?tx+nextline.right()+1:-1000000 , l-ow),
- b,
- r + ow,
- b + ow,
- BSBottom, oc, style()->color(), os,
- (nextline.isValid() && l-ow < tx+nextline.right()+1? -ow : ow),
- ow,
- true);
-}
-
void RenderInline::calcMinMaxWidth()
{
KHTMLAssert( !minMaxKnown() );
}
bool RenderInline::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inside)
+ HitTestAction hitTestAction)
{
- // Check our kids if our HitTestAction says to.
- if (hitTestAction != HitTestSelfOnly) {
- for (RenderObject* child = lastChild(); child; child = child->previousSibling())
- if (!child->layer() && !child->isFloating() && child->nodeAtPoint(info, _x, _y, _tx, _ty))
- inside = true;
- }
-
- // Check our line boxes if we're still not inside.
- if (hitTestAction != HitTestChildrenOnly && !inside && style()->visibility() != HIDDEN) {
- // See if we're inside one of our line boxes.
- for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- if((_y >=_ty + curr->m_y) && (_y < _ty + curr->m_y + curr->m_height) &&
- (_x >= _tx + curr->m_x) && (_x <_tx + curr->m_x + curr->m_width) ) {
- inside = true;
- break;
- }
- }
- }
-
- if (inside && element()) {
- if (info.innerNode() && info.innerNode()->renderer() &&
- !info.innerNode()->renderer()->isInline()) {
- // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node.
- info.setInnerNode(element());
-
- // Clear everything else.
- info.setInnerNonSharedNode(0);
- info.setURLElement(0);
- }
-
- if (!info.innerNode())
- info.setInnerNode(element());
-
- if(!info.innerNonSharedNode())
- info.setInnerNonSharedNode(element());
- }
-
- return inside;
+ return hitTestLines(info, _x, _y, _tx, _ty, hitTestAction);
}
Position RenderInline::positionForCoordinates(int x, int y, EAffinity *affinity)
virtual void paint(PaintInfo& i, int tx, int ty);
virtual bool nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
+ HitTestAction hitTestAction);
virtual void calcMinMaxWidth();
void absoluteRects(QValueList<QRect>& rects, int _tx, int _ty);
virtual DOM::Position positionForCoordinates(int x, int y, EAffinity * = 0);
-
-#ifdef APPLE_CHANGES
- virtual void addFocusRingRects(QPainter *painter, int _tx, int _ty);
- void paintFocusRing(QPainter *p, int tx, int ty);
-#endif
protected:
static RenderInline* cloneInline(RenderFlow* src);
- void paintOutline(QPainter *p, int tx, int ty, const QRect &prevLine, const QRect &thisLine, const QRect &nextLine);
- void paintOutlines(QPainter *p, int tx, int ty);
-
+
private:
bool m_isContinuation : 1; // Whether or not we're a continuation of an inline.
};
setClip(p, paintDirtyRect, damageRect);
// Paint the background.
- RenderObject::PaintInfo info(p, damageRect, PaintActionElementBackground, paintingRootForRenderer);
+ RenderObject::PaintInfo info(p, damageRect, PaintActionBlockBackground, paintingRootForRenderer);
renderer()->paint(info, x - renderer()->xPos(), y - renderer()->yPos());
#if APPLE_CHANGES
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
int tx = x - renderer()->xPos();
int ty = y - renderer()->yPos();
RenderObject::PaintInfo info(p, clipRectToApply,
- selectionOnly ? PaintActionSelection : PaintActionChildBackgrounds,
+ selectionOnly ? PaintActionSelection : PaintActionChildBlockBackgrounds,
paintingRootForRenderer);
renderer()->paint(info, tx, ty);
if (!selectionOnly) {
}
bool
-RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
+RenderLayer::hitTest(RenderObject::NodeInfo& info, int x, int y)
{
#if APPLE_CHANGES
// Clear our our scrollbar variable
#endif
QRect damageRect(m_x, m_y, width(), height());
- RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);
+ RenderLayer* insideLayer = hitTestLayer(this, info, x, y, damageRect);
// Now determine if the result is inside an anchor; make sure an image map wins if
// it already set URLElement and only use the innermost.
}
RenderLayer*
-RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
- int xMousePos, int yMousePos, const QRect& hitTestRect)
+RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
+ int xMousePos, int yMousePos, const QRect& hitTestRect)
{
// Calculate the clip rects we should use.
QRect layerBounds, bgRect, fgRect;
uint count = m_posZOrderList->count();
for (int i = count-1; i >= 0; i--) {
RenderLayer* child = m_posZOrderList->at(i);
- insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
+ insideLayer = child->hitTestLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
if (insideLayer)
return insideLayer;
}
}
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
- if (containsPoint(xMousePos, yMousePos, fgRect) &&
- renderer()->nodeAtPoint(info, xMousePos, yMousePos,
- layerBounds.x() - renderer()->xPos(),
- layerBounds.y() - renderer()->yPos(),
- HitTestChildrenOnly)) {
-
- // for positioned generated content, we might still not have a
- // node by the time we get to the layer level, since none of
- // the content in the layer has an element. So just walk up
- // the tree.
- if (!info.innerNode()) {
- for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
- if (r->element()) {
- info.setInnerNode(r->element());
- break;
- }
- }
- }
-
- if (!info.innerNonSharedNode()) {
- for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
- if (r->element()) {
- info.setInnerNonSharedNode(r->element());
- break;
- }
- }
- }
-
-
+ if (containsPoint(xMousePos, yMousePos, fgRect) &&
+ renderer()->hitTest(info, xMousePos, yMousePos,
+ layerBounds.x() - renderer()->xPos(),
+ layerBounds.y() - renderer()->yPos(), HitTestDescendants)) {
+ // for positioned generated content, we might still not have a
+ // node by the time we get to the layer level, since none of
+ // the content in the layer has an element. So just walk up
+ // the tree.
+ if (!info.innerNode()) {
+ for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
+ if (r->element()) {
+ info.setInnerNode(r->element());
+ break;
+ }
+ }
+ }
+ if (!info.innerNonSharedNode()) {
+ for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
+ if (r->element()) {
+ info.setInnerNonSharedNode(r->element());
+ break;
+ }
+ }
+ }
return this;
}
uint count = m_negZOrderList->count();
for (int i = count-1; i >= 0; i--) {
RenderLayer* child = m_negZOrderList->at(i);
- insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
+ insideLayer = child->hitTestLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
if (insideLayer)
return insideLayer;
}
// Next we want to see if the mouse pos is inside this layer but not any of its children.
if (containsPoint(xMousePos, yMousePos, bgRect) &&
- renderer()->nodeAtPoint(info, xMousePos, yMousePos,
- layerBounds.x() - renderer()->xPos(),
- layerBounds.y() - renderer()->yPos(),
- HitTestSelfOnly))
+ renderer()->hitTest(info, xMousePos, yMousePos,
+ layerBounds.x() - renderer()->xPos(),
+ layerBounds.y() - renderer()->yPos(),
+ HitTestSelf))
return this;
// No luck.
// The two main functions that use the layer system. The paint method
// paints the layers that intersect the damage rect from back to
- // front. The nodeAtPoint method looks for mouse events by walking
+ // front. The hitTest method looks for mouse events by walking
// layers that intersect the point from front to back.
void paint(QPainter *p, const QRect& damageRect, bool selectionOnly=false, RenderObject *paintingRoot=0);
- bool nodeAtPoint(RenderObject::NodeInfo& info, int x, int y);
+ bool hitTest(RenderObject::NodeInfo& info, int x, int y);
// This method figures out our layerBounds in coordinates relative to
// |rootLayer}. It also computes our background and foreground clip rects
void paintLayer(RenderLayer* rootLayer, QPainter *p, const QRect& paintDirtyRect,
bool haveTransparency, bool selectionOnly, RenderObject *paintingRoot);
- RenderLayer* nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
- int x, int y, const QRect& hitTestRect);
-
+ RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
+ int x, int y, const QRect& hitTestRect);
void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0);
protected:
m_markupBox = markupBox;
}
- void paint(RenderObject::PaintInfo& i, int _tx, int _ty);
- bool nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inBox);
+ virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty);
+ virtual bool nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty);
private:
DOM::AtomicString m_str;
m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy);
}
+void InlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
+{
+ if (!object()->shouldPaintWithinRoot(i) || i.phase == PaintActionOutline)
+ return;
+
+ // Paint all phases of replaced elements atomically, as though the replaced element established its
+ // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
+ // specification.)
+ bool paintSelectionOnly = i.phase == PaintActionSelection;
+ RenderObject::PaintInfo info(i.p, i.r, paintSelectionOnly ? i.phase : PaintActionBlockBackground, i.paintingRoot);
+ object()->paint(info, tx, ty);
+ if (!paintSelectionOnly) {
+ info.phase = PaintActionChildBlockBackgrounds;
+ object()->paint(info, tx, ty);
+ info.phase = PaintActionFloat;
+ object()->paint(info, tx, ty);
+ info.phase = PaintActionForeground;
+ object()->paint(info, tx, ty);
+ info.phase = PaintActionOutline;
+ object()->paint(info, tx, ty);
+ }
+}
+
+bool InlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
+{
+ // Hit test all phases of replaced elements atomically, as though the replaced element established its
+ // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
+ // specification.)
+ return object()->hitTest(i, x, y, tx, ty);
+}
+
RootInlineBox* InlineBox::root()
{
if (m_parent)
return -1;
}
+RenderFlow* InlineFlowBox::flowObject()
+{
+ return static_cast<RenderFlow*>(m_object);
+}
+
int InlineFlowBox::marginLeft()
{
if (!includeLeftEdge())
}
}
+bool InlineFlowBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
+{
+ // Check children first.
+ for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
+ if (!curr->object()->layer() && curr->nodeAtPoint(i, x, y, tx, ty)) {
+ object()->setInnerNode(i);
+ return true;
+ }
+ }
+
+ // Now check ourselves.
+ QRect rect(tx + m_x, ty + m_y, m_width, m_height);
+ if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
+ object()->setInnerNode(i);
+ return true;
+ }
+
+ return false;
+}
+
+void InlineFlowBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
+{
+ bool intersectsDamageRect = true;
+ int xPos = tx + m_x - object()->maximalOutlineSize(i.phase);
+ int w = width() + 2 * object()->maximalOutlineSize(i.phase);
+ if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x()))
+ intersectsDamageRect = false;
+
+ if (intersectsDamageRect) {
+ if (i.phase == PaintActionOutline) {
+ // Add ourselves to the paint info struct's list of inlines that need to paint their
+ // outlines.
+ if (object()->style()->visibility() == VISIBLE && object()->style()->outlineWidth() > 0 &&
+ !object()->isInlineContinuation()) {
+ if (!i.outlineObjects)
+ i.outlineObjects = new QPtrDict<RenderFlow>;
+ if (!i.outlineObjects->find(flowObject()))
+ i.outlineObjects->insert(flowObject(), flowObject());
+ }
+ }
+ else {
+ // 1. Paint our background and border.
+ paintBackgroundAndBorder(i, tx, ty);
+
+ // 2. Paint our underline and overline.
+ paintDecorations(i, tx, ty, false);
+ }
+ }
+
+ // 3. Paint our children.
+ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
+ if (!curr->object()->layer())
+ curr->paint(i, tx, ty);
+ }
+
+ // 4. Paint our strike-through
+ if (intersectsDamageRect && i.phase != PaintActionOutline)
+ paintDecorations(i, tx, ty, true);
+}
+
void InlineFlowBox::paintBackgrounds(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
- int my, int mh, int _tx, int _ty, int w, int h, int xoff)
+ int my, int mh, int _tx, int _ty, int w, int h)
{
if (!bgLayer)
return;
- paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h, xoff);
- paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h, xoff);
+ paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h);
+ paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h);
}
void InlineFlowBox::paintBackground(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
- int my, int mh, int _tx, int _ty, int w, int h, int xOffsetOnLine)
+ int my, int mh, int _tx, int _ty, int w, int h)
{
CachedImage* bg = bgLayer->backgroundImage();
bool hasBackgroundImage = bg && (bg->pixmap_size() == bg->valid_rect().size()) &&
// strip. Even though that strip has been broken up across multiple lines, you still paint it
// as though you had one single line. This means each line has to pick up the background where
// the previous line left off.
+ int xOffsetOnLine = 0;
+ for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
+ xOffsetOnLine += curr->width();
int startX = _tx - xOffsetOnLine;
int totalWidth = xOffsetOnLine;
for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
}
}
-void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty, int xOffsetOnLine)
+void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty)
{
+ if (!object()->shouldPaintWithinRoot(i) || object()->style()->visibility() != VISIBLE ||
+ i.phase != PaintActionForeground)
+ return;
+
// Move x/y to our coordinates.
_tx += m_x;
_ty += m_y;
if ((!parent() && m_firstLine && styleToUse != object()->style()) ||
(parent() && object()->shouldPaintBackgroundOrBorder())) {
QColor c = styleToUse->backgroundColor();
- paintBackgrounds(p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h, xOffsetOnLine);
+ paintBackgrounds(p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h);
// :first-line cannot be used to put borders on a line. Always paint borders with our
// non-first-line style.
void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren)
{
- // Now paint our text decorations. We only do this if we aren't in quirks mode (i.e., in
+ // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
// almost-strict mode or strict mode).
+ if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(i) ||
+ object()->style()->visibility() != VISIBLE)
+ return;
+
QPainter* p = i.p;
_tx += m_x;
_ty += m_y;
// Paint the markup box
_tx += m_x + m_width - m_markupBox->xPos();
_ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
- m_markupBox->object()->paint(i, _tx, _ty);
+ m_markupBox->paint(i, _tx, _ty);
}
}
-bool EllipsisBox::nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inBox)
+bool EllipsisBox::nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty)
{
+ // Hit test the markup box.
if (m_markupBox) {
_tx += m_x + m_width - m_markupBox->xPos();
_ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
- inBox |= m_markupBox->object()->nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
+ if (m_markupBox->nodeAtPoint(info, _x, _y, _tx, _ty)) {
+ object()->setInnerNode(info);
+ return true;
+ }
}
-
- return inBox;
+
+ QRect rect(_tx + m_x, _ty + m_y, m_width, m_height);
+ if (object()->style()->visibility() == VISIBLE && rect.contains(_x, _y)) {
+ object()->setInnerNode(info);
+ return true;
+ }
+ return false;
}
void RootInlineBox::detach(RenderArena* arena)
void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& i, int _tx, int _ty) const
{
- if (m_ellipsisBox)
+ if (m_ellipsisBox && object()->shouldPaintWithinRoot(i) && object()->style()->visibility() == VISIBLE &&
+ i.phase == PaintActionForeground)
m_ellipsisBox->paint(i, _tx, _ty);
}
-bool RootInlineBox::hitTestEllipsisBox(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inBox)
+void RootInlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
+{
+ InlineFlowBox::paint(i, tx, ty);
+ paintEllipsisBox(i, tx, ty);
+}
+
+bool RootInlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
{
- if (m_ellipsisBox)
- inBox |= m_ellipsisBox->nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
- return inBox;
+ if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) {
+ if (m_ellipsisBox->nodeAtPoint(i, x, y, tx, ty)) {
+ object()->setInnerNode(i);
+ return true;
+ }
+ }
+ return InlineFlowBox::nodeAtPoint(i, x, y, tx, ty);
}
void RootInlineBox::adjustPosition(int dx, int dy)
class InlineFlowBox;
class RootInlineBox;
class RenderBlock;
+class RenderFlow;
// InlineBox represents a rectangle that occurs on a line. It corresponds to
// some RenderObject (i.e., it represents a portion of that RenderObject).
virtual void adjustPosition(int dx, int dy);
+ virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty);
+ virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty);
+
// Overloaded new operator.
void* operator new(size_t sz, RenderArena* renderArena) throw();
void setNextLineBox(InlineRunBox* n) { m_nextLine = n; }
void setPreviousLineBox(InlineRunBox* p) { m_prevLine = p; }
- virtual void paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty, int xOffsetOnLine) {};
+ virtual void paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty) {};
virtual void paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren = false) {};
protected:
m_hasTextChildren = false;
}
+ RenderFlow* flowObject();
+
virtual bool isInlineFlowBox() { return true; }
InlineFlowBox* prevFlowBox() const { return static_cast<InlineFlowBox*>(m_prevLine); }
virtual void clearTruncation();
- virtual void paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty, int xOffsetOnLine);
+ virtual void paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty);
void paintBackgrounds(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
- int my, int mh, int _tx, int _ty, int w, int h, int xoff);
+ int my, int mh, int _tx, int _ty, int w, int h);
void paintBackground(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
- int my, int mh, int _tx, int _ty, int w, int h, int xoff);
+ int my, int mh, int _tx, int _ty, int w, int h);
virtual void paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren = false);
-
+ virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty);
+ virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty);
+
int marginBorderPaddingLeft();
int marginBorderPaddingRight();
int marginLeft();
virtual void clearTruncation();
+ virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty);
+ virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty);
+
bool hasSelectedChildren() const { return m_hasSelectedChildren; }
void setHasSelectedChildren(bool b);
continuation()->updateDragState(dragOn);
}
-bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inside)
+bool RenderObject::hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
{
- int tx = _tx + xPos();
- int ty = _ty + yPos();
+ bool inside = false;
+ if (hitTestFilter != HitTestSelf) {
+ // First test the foreground layer (lines and inlines).
+ inside = nodeAtPoint(info, x, y, tx, ty, HitTestForeground);
+
+ // Test floats next.
+ if (!inside)
+ inside = nodeAtPoint(info, x, y, tx, ty, HitTestFloat);
- QRect boundsRect(tx, ty, width(), height());
- inside |= (style()->visibility() != HIDDEN && boundsRect.contains(_x, _y)) || isBody() || isRoot();
- bool inOverflowRect = inside;
- if (!inOverflowRect) {
- QRect overflowRect(tx, ty, overflowWidth(false), overflowHeight(false));
- inOverflowRect = overflowRect.contains(_x, _y);
+ // Finally test to see if the mouse is in the background (within a child block's background).
+ if (!inside)
+ inside = nodeAtPoint(info, x, y, tx, ty, HitTestChildBlockBackgrounds);
}
- // ### table should have its own, more performant method
- if (hitTestAction != HitTestSelfOnly &&
- ((!isRenderBlock() ||
- !static_cast<RenderBlock*>(this)->isPointInScrollbar(_x, _y, _tx, _ty)) &&
- (inOverflowRect || isInline() || isCanvas() ||
- isTableRow() || isTableSection() || inside || mouseInside() ||
- (childrenInline() && firstChild() && firstChild()->isCompact())))) {
- if (hitTestAction == HitTestChildrenOnly)
- inside = false;
- int stx = _tx + xPos();
- int sty = _ty + yPos();
- if (hasOverflowClip())
- layer()->subtractScrollOffset(stx, sty);
- for (RenderObject* child = lastChild(); child; child = child->previousSibling())
- if (!child->layer() && !child->isFloating() &&
- child->nodeAtPoint(info, _x, _y, stx, sty))
- inside = true;
- }
-
- if (inside) {
- if (!info.innerNode() && !isInline() && continuation()) {
- // We are in the margins of block elements that are part of a continuation. In
- // this case we're actually still inside the enclosing inline element that was
- // split. Go ahead and set our inner node accordingly.
- info.setInnerNode(continuation()->element());
- if (!info.innerNonSharedNode())
- info.setInnerNonSharedNode(continuation()->element());
- }
-
- if (info.innerNode() && info.innerNode()->renderer() &&
- !info.innerNode()->renderer()->isInline() && element() && isInline()) {
- // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node.
- info.setInnerNode(element());
-
- // Clear everything else.
- info.setInnerNonSharedNode(0);
- info.setURLElement(0);
- }
+ // See if the mouse is inside us but not any of our descendants
+ if (hitTestFilter != HitTestDescendants && !inside)
+ inside = nodeAtPoint(info, x, y, tx, ty, HitTestBlockBackground);
- if (!info.innerNode() && element())
- info.setInnerNode(element());
+ return inside;
+}
- if(!info.innerNonSharedNode() && element())
- info.setInnerNonSharedNode(element());
+void RenderObject::setInnerNode(NodeInfo& info)
+{
+ if (!info.innerNode() && !isInline() && continuation()) {
+ // We are in the margins of block elements that are part of a continuation. In
+ // this case we're actually still inside the enclosing inline element that was
+ // split. Go ahead and set our inner node accordingly.
+ info.setInnerNode(continuation()->element());
+ if (!info.innerNonSharedNode())
+ info.setInnerNonSharedNode(continuation()->element());
}
- return inside;
+ if (!info.innerNode() && element())
+ info.setInnerNode(element());
+
+ if(!info.innerNonSharedNode() && element())
+ info.setInnerNonSharedNode(element());
+}
+
+bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+ HitTestAction hitTestAction)
+{
+ return false;
}
short RenderObject::verticalPositionHint( bool firstLine ) const
*/
typedef enum {
- PaintActionElementBackground = 0,
- PaintActionChildBackground,
- PaintActionChildBackgrounds,
+ PaintActionBlockBackground,
+ PaintActionChildBlockBackground,
+ PaintActionChildBlockBackgrounds,
PaintActionFloat,
PaintActionForeground,
PaintActionOutline,
} PaintAction;
typedef enum {
- HitTestAll = 0,
- HitTestSelfOnly = 1,
- HitTestChildrenOnly = 2
+ HitTestAll,
+ HitTestSelf,
+ HitTestDescendants
+} HitTestFilter;
+
+typedef enum {
+ HitTestBlockBackground,
+ HitTestChildBlockBackground,
+ HitTestChildBlockBackgrounds,
+ HitTestFloat,
+ HitTestForeground
} HitTestAction;
namespace DOM {
*/
struct PaintInfo {
PaintInfo(QPainter* _p, const QRect& _r, PaintAction _phase, RenderObject *_paintingRoot)
- : p(_p), r(_r), phase(_phase), paintingRoot(_paintingRoot) {}
+ : p(_p), r(_r), phase(_phase), paintingRoot(_paintingRoot), outlineObjects(0) {}
+ ~PaintInfo() { delete outlineObjects; }
QPainter* p;
QRect r;
PaintAction phase;
RenderObject *paintingRoot; // used to draw just one element and its visual kids
+ QPtrDict<RenderFlow>* outlineObjects; // used to list which outlines should be painted by a block with inline children
};
virtual void paint(PaintInfo& i, int tx, int ty);
void paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin=true, bool end=true);
RepaintInfo(RenderObject* o, const QRect& r) :m_object(o), m_repaintRect(r) {}
};
+ bool hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter = HitTestAll);
virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
-
+ HitTestAction hitTestAction);
+ void setInnerNode(NodeInfo& info);
+
virtual DOM::Position positionForCoordinates(int x, int y, EAffinity * = 0);
virtual void dirtyLinesFromChangedChild(RenderObject* child, bool adding = true);
virtual void selectionStartEnd(int& spos, int& epos);
+ RenderObject* paintingRootForChildren(PaintInfo &i) const {
+ // if we're the painting root, kids draw normally, and see root of 0
+ return (!i.paintingRoot || i.paintingRoot == this) ? 0 : i.paintingRoot;
+ }
+
+ bool shouldPaintWithinRoot(PaintInfo &i) const {
+ return !i.paintingRoot || i.paintingRoot == this;
+ }
+
protected:
virtual void printBoxDecorations(QPainter* /*p*/, int /*_x*/, int /*_y*/,
void arenaDelete(RenderArena *arena);
- RenderObject *paintingRootForChildren(PaintInfo &i) const {
- // if we're the painting root, kids draw normally, and see root of 0
- return (!i.paintingRoot || i.paintingRoot == this) ? 0 : i.paintingRoot;
- }
- bool shouldPaintWithinRoot(PaintInfo &i) const {
- return !i.paintingRoot || i.paintingRoot == this;
- }
-
private:
RenderStyle* m_style;
if (checkForRepaint)
repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds);
+ m_overflowHeight = kMax(m_overflowHeight, m_height);
+
setNeedsLayout(false);
}
#ifdef TABLE_PRINT
kdDebug( 6040 ) << "RenderTable::paint() w/h = (" << width() << "/" << height() << ")" << endl;
#endif
- if (!isRelPositioned() && !isPositioned()) {
- int os = 2*maximalOutlineSize(paintAction);
- if ((_ty >= i.r.y() + i.r.height() + os) || (_ty + height() <= i.r.y() - os)) return;
- if ((_tx >= i.r.x() + i.r.width() + os) || (_tx + width() <= i.r.x() - os)) return;
- }
+
+ int os = 2*maximalOutlineSize(paintAction);
+ if ((_ty >= i.r.y() + i.r.height() + os) || (_ty + height() <= i.r.y() - os)) return;
+ if ((_tx >= i.r.x() + i.r.width() + os) || (_tx + width() <= i.r.x() - os)) return;
#ifdef TABLE_PRINT
kdDebug( 6040 ) << "RenderTable::paint(2) " << _tx << "/" << _ty << " (" << _y << "/" << _h << ")" << endl;
#endif
- if ((paintAction == PaintActionElementBackground || paintAction == PaintActionChildBackground)
+ if ((paintAction == PaintActionBlockBackground || paintAction == PaintActionChildBlockBackground)
&& shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE)
paintBoxDecorations(i, _tx, _ty);
// We're done. We don't bother painting any children.
- if (paintAction == PaintActionElementBackground)
+ if (paintAction == PaintActionBlockBackground)
return;
// We don't paint our own background, but we do let the kids paint their backgrounds.
- if (paintAction == PaintActionChildBackgrounds)
- paintAction = PaintActionChildBackground;
+ if (paintAction == PaintActionChildBlockBackgrounds)
+ paintAction = PaintActionChildBlockBackground;
PaintInfo paintInfo(i.p, i.r, paintAction, paintingRootForChildren(i));
for (RenderObject *child = firstChild(); child; child = child->nextSibling())
if (child->isTableSection() || child == tCaption)
child->paint(paintInfo, _tx, _ty);
- if (collapseBorders() && paintAction == PaintActionChildBackground && style()->visibility() == VISIBLE) {
+ if (collapseBorders() && paintAction == PaintActionChildBlockBackground && style()->visibility() == VISIBLE) {
// Collect all the unique border styles that we want to paint in a sorted list. Once we
// have all the styles sorted, we then do individual passes, painting each style of border
// from lowest precedence to highest precedence.
return -1;
}
-void InlineTextBox::paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos)
+static int
+simpleDifferenceBetweenColors(QColor c1, QColor c2)
{
- int offset = m_start;
- int sPos = kMax(startPos - offset, 0);
- int ePos = kMin(endPos - offset, (int)m_len);
+ // a distance could be computed by squaring the differences between components, but
+ // this is faster and so far seems good enough for our purposes.
+ return abs(c1.red() - c2.red()) + abs(c1.green() - c2.green()) + abs(c1.blue() - c2.blue());
+}
+
+static QColor
+correctedTextColor(QColor textColor, QColor backgroundColor)
+{
+ // Adjust the text color if it is too close to the background color,
+ // by darkening or lightening it to move it further away.
+
+ int d = simpleDifferenceBetweenColors(textColor, backgroundColor);
+ // semi-arbitrarily chose 255 value here after a few tests;
+ if (d > 255) {
+ return textColor;
+ }
+
+ int distanceFromWhite = simpleDifferenceBetweenColors(textColor, Qt::white);
+ int distanceFromBlack = simpleDifferenceBetweenColors(textColor, Qt::black);
+
+ if (distanceFromWhite < distanceFromBlack) {
+ return textColor.dark();
+ }
+
+ return textColor.light();
+}
+
+bool InlineTextBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty)
+{
+ if (object()->isBR())
+ return false;
+
+ QRect rect(tx + m_x, ty + m_y, m_width, m_height);
+ if (m_truncation != cFullTruncation &&
+ object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
+ object()->setInnerNode(i);
+ return true;
+ }
+ return false;
+}
+
+void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
+{
+ if (object()->isBR() || !object()->shouldPaintWithinRoot(i) || object()->style()->visibility() != VISIBLE ||
+ m_truncation == cFullTruncation || i.phase == PaintActionOutline)
+ return;
+
+ int xPos = tx + m_x;
+ int w = width();
+ if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x()))
+ return;
+
+ bool isPrinting = (i.p->device()->devType() == QInternal::Printer);
+
+ // Determine whether or not we're selected.
+ bool haveSelection = !isPrinting && selectionState() != RenderObject::SelectionNone;
+ if (!haveSelection && i.phase == PaintActionSelection)
+ // When only painting the selection, don't bother to paint if there is none.
+ return;
+
+ // Determine whether or not we have marked text.
+ Range markedTextRange = KWQ(object()->document()->part())->markedTextRange();
+ bool haveMarkedText = markedTextRange.handle() != 0 && markedTextRange.startContainer() == object()->node();
+
+ // Set our font.
+ RenderStyle* styleToUse = object()->style(m_firstLine);
+ int d = styleToUse->textDecorationsInEffect();
+ if (styleToUse->font() != i.p->font())
+ i.p->setFont(styleToUse->font());
+ const Font *font = &styleToUse->htmlFont();
+
+ // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
+ // and marked text.
+ if ((haveSelection || haveMarkedText) && i.phase != PaintActionSelection && !isPrinting) {
+ if (haveMarkedText)
+ paintMarkedTextBackground(i.p, tx, ty, styleToUse, font, markedTextRange.startOffset(), markedTextRange.endOffset());
+
+ if (haveSelection)
+ paintSelection(i.p, tx, ty, styleToUse, font);
+ }
+
+ // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
+ if (m_len <= 0) return;
+ QValueList<DocumentMarker> markers = object()->document()->markersForNode(object()->node());
+ QValueListIterator <DocumentMarker> markerIt = markers.begin();
+
+ QColor textColor = styleToUse->color();
+ if (styleToUse->shouldCorrectTextColor())
+ textColor = correctedTextColor(textColor, styleToUse->backgroundColor());
+
+ if (textColor != i.p->pen().color())
+ i.p->setPen(textColor);
+
+ // Set a text shadow if we have one.
+ // FIXME: Support multiple shadow effects. Need more from the CG API before
+ // we can do this.
+ bool setShadow = false;
+ if (styleToUse->textShadow()) {
+ i.p->setShadow(styleToUse->textShadow()->x, styleToUse->textShadow()->y,
+ styleToUse->textShadow()->blur, styleToUse->textShadow()->color);
+ setShadow = true;
+ }
+
+ bool paintSelectedTextOnly = (i.phase == PaintActionSelection);
+ bool paintSelectedTextSeparately = false; // Whether or not we have to do multiple paints. Only
+ // necessary when a custom ::selection foreground color is applied.
+ QColor selectionColor = i.p->pen().color();
+ ShadowData* selectionTextShadow = 0;
+ if (haveSelection) {
+ RenderStyle* pseudoStyle = object()->getPseudoStyle(RenderStyle::SELECTION);
+ if (pseudoStyle) {
+ if (pseudoStyle->color() != selectionColor || pseudoStyle->textShadow()) {
+ if (!paintSelectedTextOnly)
+ paintSelectedTextSeparately = true;
+ if (pseudoStyle->color() != selectionColor)
+ selectionColor = pseudoStyle->color();
+ if (pseudoStyle->textShadow())
+ selectionTextShadow = pseudoStyle->textShadow();
+ }
+ }
+ }
+
+ if (!paintSelectedTextOnly && !paintSelectedTextSeparately) {
+ // paint all the text
+ // FIXME: Handle RTL direction, handle reversed strings. For now truncation can only be turned on
+ // for non-reversed LTR strings.
+ int endPoint = m_len;
+ if (m_truncation != cNoTruncation)
+ endPoint = m_truncation - m_start;
+ font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
+ textObject()->string()->s, textObject()->string()->l, m_start, endPoint,
+ m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
+ } else {
+ int sPos, ePos;
+ selectionStartEnd(sPos, ePos);
+ if (paintSelectedTextSeparately) {
+ // paint only the text that is not selected
+ if (sPos >= ePos) {
+ font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
+ textObject()->string()->s, textObject()->string()->l, m_start, m_len,
+ m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
+ } else {
+ if (sPos - 1 >= 0) {
+ font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
+ textObject()->string()->l, m_start, m_len,
+ m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), 0, sPos);
+ }
+ if (ePos < m_start + m_len) {
+ font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
+ textObject()->string()->l, m_start, m_len,
+ m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), ePos, -1);
+ }
+ }
+ }
+
+ if (sPos < ePos) {
+ // paint only the text that is selected
+ if (selectionColor != i.p->pen().color())
+ i.p->setPen(selectionColor);
+
+ if (selectionTextShadow)
+ i.p->setShadow(selectionTextShadow->x,
+ selectionTextShadow->y,
+ selectionTextShadow->blur,
+ selectionTextShadow->color);
+ font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
+ textObject()->string()->l, m_start, m_len,
+ m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), sPos, ePos);
+ if (selectionTextShadow)
+ i.p->clearShadow();
+ }
+ }
+
+ // Paint decorations
+ if (d != TDNONE && i.phase != PaintActionSelection && styleToUse->htmlHacks()) {
+ i.p->setPen(styleToUse->color());
+ paintDecoration(i.p, tx, ty, d);
+ }
+
+ // Draw any doc markers that touch this run
+ // Note end() points at the last char, not one past it like endOffset and ranges do
+ if (i.phase != PaintActionSelection) {
+ for ( ; markerIt != markers.end(); markerIt++) {
+ DocumentMarker marker = *markerIt;
+
+ if (marker.endOffset <= start())
+ // marker is completely before this run. This might be a marker that sits before the
+ // first run we draw, or markers that were within runs we skipped due to truncation.
+ continue;
+
+ if (marker.startOffset <= end()) {
+ // marker intersects this run. Paint it.
+ paintMarker(i.p, tx, ty, marker);
+ if (marker.endOffset > end() + 1)
+ // marker also runs into the next run. Bail now, no more marker advancement.
+ break;
+ } else
+ // marker is completely after this run, bail. A later run will paint it.
+ break;
+ }
+ }
+
+ if (setShadow)
+ i.p->clearShadow();
+}
+
+void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
+{
+ int startPos, endPos;
+ if (object()->selectionState() == RenderObject::SelectionInside) {
+ startPos = 0;
+ endPos = textObject()->string()->l;
+ } else {
+ textObject()->selectionStartEnd(startPos, endPos);
+ if (object()->selectionState() == RenderObject::SelectionStart)
+ endPos = textObject()->string()->l;
+ else if (object()->selectionState() == RenderObject::SelectionEnd)
+ startPos = 0;
+ }
+
+ sPos = kMax(startPos - m_start, 0);
+ ePos = kMin(endPos - m_start, (int)m_len);
+}
+void InlineTextBox::paintSelection(QPainter* p, int tx, int ty, RenderStyle* style, const Font* f)
+{
+ // See if we have a selection to paint at all.
+ int sPos, ePos;
+ selectionStartEnd(sPos, ePos);
if (sPos >= ePos)
return;
int y = r->selectionTop();
int h = r->selectionHeight();
f->drawHighlightForText(p, x, y + ty, h,
- text->str->s, text->str->l, m_start, m_len,
+ textObject()->str->s, textObject()->str->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
p->restore();
}
-#if APPLE_CHANGES
-void InlineTextBox::paintMarkedTextBackground(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos)
+void InlineTextBox::paintMarkedTextBackground(QPainter* p, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
{
int offset = m_start;
int sPos = kMax(startPos - offset, 0);
int x = m_x + tx;
int y = r->selectionTop();
int h = r->selectionHeight();
- f->drawHighlightForText(p, x, y + ty, h, text->str->s, text->str->l, m_start, m_len,
+ f->drawHighlightForText(p, x, y + ty, h, textObject()->str->s, textObject()->str->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
p->restore();
}
-#endif
-#ifdef APPLE_CHANGES
void InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int deco)
{
_tx += m_x;
pt->drawLineForText(_tx, _ty, 2*m_baseline/3, width);
}
}
-#else
-void InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int decoration)
-{
- _tx += m_x;
- _ty += m_y;
-
- int width = m_width - 1;
-
- QColor underline, overline, linethrough;
- object()->getTextDecorationColors(decoration, underline, overline, linethrough, true);
-
- int underlineOffset = ( pt->fontMetrics().height() + m_baseline ) / 2;
- if(underlineOffset <= m_baseline) underlineOffset = m_baseline+1;
-
- if(deco & UNDERLINE){
- pt->setPen(underline);
- pt->drawLine(_tx, _ty + underlineOffset, _tx + width, _ty + underlineOffset );
- }
- if (deco & OVERLINE) {
- pt->setPen(overline);
- pt->drawLine(_tx, _ty, _tx + width, _ty );
- }
- if(deco & LINE_THROUGH) {
- pt->setPen(linethrough);
- pt->drawLine(_tx, _ty + 2*m_baseline/3, _tx + width, _ty + 2*m_baseline/3 );
- }
- // NO! Do NOT add BLINK! It is the most annouing feature of Netscape, and IE has a reason not to
- // support it. Lars
-}
-#endif
void InlineTextBox::paintMarker(QPainter *pt, int _tx, int _ty, DocumentMarker marker)
{
return s;
}
-bool RenderText::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
- HitTestAction hitTestAction, bool inside)
-{
- assert(parent());
-
- if (style()->visibility() == HIDDEN)
- return inside;
-
- for (InlineTextBox *s = m_firstTextBox; s; s = s->nextTextBox()) {
- if((_y >=_ty + s->m_y) && (_y < _ty + s->m_y + s->height()) &&
- (_x >= _tx + s->m_x) && (_x <_tx + s->m_x + s->m_width) ) {
- inside = true;
- break;
- }
- }
-
- if (inside && element()) {
- if (info.innerNode() && info.innerNode()->renderer() &&
- !info.innerNode()->renderer()->isInline()) {
- // Within the same layer, inlines are ALWAYS fully above blocks. Change inner node.
- info.setInnerNode(element());
-
- // Clear everything else.
- info.setInnerNonSharedNode(0);
- info.setURLElement(0);
- }
-
- if (!info.innerNode())
- info.setInnerNode(element());
-
- if (!info.innerNonSharedNode())
- info.setInnerNonSharedNode(element());
- }
-
- return inside;
-}
-
Position RenderText::positionForCoordinates(int _x, int _y, EAffinity *affinity)
{
if (affinity)
}
}
-static int
-simpleDifferenceBetweenColors(QColor c1, QColor c2)
-{
- // a distance could be computed by squaring the differences between components, but
- // this is faster and so far seems good enough for our purposes.
- return abs(c1.red() - c2.red()) + abs(c1.green() - c2.green()) + abs(c1.blue() - c2.blue());
-}
-
-static QColor
-correctedTextColor(QColor textColor, QColor backgroundColor)
-{
- // Adjust the text color if it is too close to the background color,
- // by darkening or lightening it to move it further away.
-
- int d = simpleDifferenceBetweenColors(textColor, backgroundColor);
- // semi-arbitrarily chose 255 value here after a few tests;
- if (d > 255) {
- return textColor;
- }
-
- int distanceFromWhite = simpleDifferenceBetweenColors(textColor, Qt::white);
- int distanceFromBlack = simpleDifferenceBetweenColors(textColor, Qt::black);
-
- if (distanceFromWhite < distanceFromBlack) {
- return textColor.dark();
- }
-
- return textColor.light();
-}
-
-void RenderText::paint(PaintInfo& i, int tx, int ty)
-{
- if (i.phase != PaintActionForeground && i.phase != PaintActionSelection)
- return;
-
- if (!shouldPaintWithinRoot(i))
- return;
-
- if (style()->visibility() != VISIBLE || !firstTextBox())
- return;
-
- // Selection paints all the way up to the previous line's bottomOverflow. We need to check
- // for this when doing our dirty rect intersection tests.
- int topY = firstTextBox()->yPos();
- if (firstTextBox()->root()->hasSelectedChildren())
- topY = kMin(topY, firstTextBox()->root()->selectionTop());
- int bottomY = lastTextBox()->yPos() + lastTextBox()->height();
- if (lastTextBox()->root()->hasSelectedChildren())
- bottomY = kMax(bottomY, lastTextBox()->root()->bottomOverflow());
-
- if (ty + topY >= i.r.y() + i.r.height())
- return;
-
- if (ty + bottomY <= i.r.y())
- return;
-
- QPainter* p = i.p;
- RenderStyle* pseudoStyle = style(true);
- if (pseudoStyle == style()) pseudoStyle = 0;
- int d = style()->textDecorationsInEffect();
- bool isPrinting = (p->device()->devType() == QInternal::Printer);
-
- // Walk forward until we hit the first line that needs to be painted.
- InlineTextBox* s = firstTextBox();
- for (; s && !s->checkVerticalPoint(i.r.y(), ty, i.r.height()); s = s->nextTextBox());
- if (!s) return;
-
- // Now calculate startPos and endPos, for painting selection.
- // We paint selection while endPos > 0
- int endPos, startPos;
- if (!isPrinting && (selectionState() != SelectionNone)) {
- if (selectionState() == SelectionInside) {
- //kdDebug(6040) << this << " SelectionInside -> 0 to end" << endl;
- startPos = 0;
- endPos = str->l;
- } else {
- selectionStartEnd(startPos, endPos);
- if(selectionState() == SelectionStart)
- endPos = str->l;
- else if(selectionState() == SelectionEnd)
- startPos = 0;
- }
- //kdDebug(6040) << this << " Selection from " << startPos << " to " << endPos << endl;
- }
-
- const Font *font = &style()->htmlFont();
-
-#if APPLE_CHANGES
- // We will iterate over the text boxes in two passes. First we
- // paint all the backgrounds, then the foregrounds.
-
- InlineTextBox* startBox = s;
-
- // Pass 1: paint backgrounds for selection or marked text, if we have any
-
- bool haveSelection = startPos != endPos && !isPrinting && selectionState() != SelectionNone;
- if (!haveSelection && i.phase == PaintActionSelection) {
- // When only painting the selection, don't bother to paint if there is none.
- return;
- }
-
- Range markedTextRange = KWQ(document()->part())->markedTextRange();
- bool haveMarkedText = markedTextRange.handle() != 0 && markedTextRange.startContainer() == node();
-
- if ((haveSelection || haveMarkedText) && i.phase != PaintActionSelection && !isPrinting) {
- s = startBox;
-
- // run until we find a text box that is outside the range, then we know we can stop
- do {
- if (s->m_truncation == cFullTruncation)
- continue;
-
- RenderStyle* _style = pseudoStyle && s->m_firstLine ? pseudoStyle : style();
-
- if (_style->font() != p->font())
- p->setFont(_style->font());
-
- font = &_style->htmlFont(); // Always update, since smallCaps is not stored in the QFont.
-
- if (haveMarkedText)
- s->paintMarkedTextBackground(font, this, p, _style, tx, ty, markedTextRange.startOffset(), markedTextRange.endOffset());
-
- if (haveSelection)
- s->paintSelection(font, this, p, _style, tx, ty, startPos, endPos);
-
- } while (((s = s->nextTextBox()) != 0) && s->checkVerticalPoint(i.r.y(), ty, i.r.height()));
- }
-
-
- // Pass 2: now paint the foreground, including text and decorations
-
- QValueList<DocumentMarker> markers = document()->markersForNode(node());
- QValueListIterator <DocumentMarker> markerIt = markers.begin();
-
- s = startBox;
-
- // run until we find a text box that is outside the range, then we know we can stop
- do {
- if (isPrinting) {
- if (ty+s->m_y+s->height() > i.r.y() + i.r.height()) {
- RenderCanvas* canvasObj = canvas();
- if (ty+s->m_y < canvasObj->truncatedAt())
- canvasObj->setBestTruncatedAt(ty+s->m_y, this);
- // Let's stop here.
- break;
- }
- }
-
- if (s->m_truncation == cFullTruncation)
- continue;
-
- RenderStyle* _style = pseudoStyle && s->m_firstLine ? pseudoStyle : style();
-
- if (_style->font() != p->font())
- p->setFont(_style->font());
-
- font = &_style->htmlFont(); // Always update, since smallCaps is not stored in the QFont.
-
- QColor textColor = _style->color();
- if (_style->shouldCorrectTextColor()) {
- textColor = correctedTextColor(textColor, _style->backgroundColor());
- }
-
- if(textColor != p->pen().color())
- p->setPen(textColor);
-
- // Set a text shadow if we have one.
- // FIXME: Support multiple shadow effects. Need more from the CG API before
- // we can do this.
- bool setShadow = false;
- if (_style->textShadow()) {
- p->setShadow(_style->textShadow()->x, _style->textShadow()->y,
- _style->textShadow()->blur, _style->textShadow()->color);
- setShadow = true;
- }
-
- if (s->m_len > 0) {
- bool paintSelectedTextOnly = (i.phase == PaintActionSelection);
- bool paintSelectedTextSeparately = false; // Whether or not we have to do multiple paints. Only
- // necessary when a custom ::selection foreground color is applied.
- QColor selectionColor = p->pen().color();
- ShadowData* selectionTextShadow = 0;
- if (haveSelection) {
- RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
- if (pseudoStyle) {
- if (pseudoStyle->color() != selectionColor || pseudoStyle->textShadow()) {
- if (!paintSelectedTextOnly)
- paintSelectedTextSeparately = true;
- if (pseudoStyle->color() != selectionColor)
- selectionColor = pseudoStyle->color();
- if (pseudoStyle->textShadow())
- selectionTextShadow = pseudoStyle->textShadow();
- }
- }
- }
-
- if (!paintSelectedTextOnly && !paintSelectedTextSeparately) {
- // paint all the text
-
- // FIXME: Handle RTL direction, handle reversed strings. For now truncation can only be turned on
- // for non-reversed LTR strings.
- int endPoint = s->m_len;
- if (s->m_truncation != cNoTruncation)
- endPoint = s->m_truncation - s->m_start;
- font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline,
- str->s, str->l, s->m_start, endPoint,
- s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered());
- } else {
- int offset = s->m_start;
- int sPos = QMAX( startPos - offset, 0 );
- int ePos = QMIN( endPos - offset, s->m_len );
- if (paintSelectedTextSeparately) {
- // paint only the text that is not selected
-
- if (sPos >= ePos) {
- font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline,
- str->s, str->l, s->m_start, s->m_len,
- s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered());
- } else {
- if (sPos-1 >= 0) {
- font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s,
- str->l, s->m_start, s->m_len,
- s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered(), 0, sPos);
- }
- if (ePos < s->m_start+s->m_len) {
- font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s,
- str->l, s->m_start, s->m_len,
- s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered(), ePos, -1);
- }
- }
- }
-
- if ( sPos < ePos ) {
- // paint only the text that is selected
- if (selectionColor != p->pen().color())
- p->setPen(selectionColor);
-
- if (selectionTextShadow)
- p->setShadow(selectionTextShadow->x,
- selectionTextShadow->y,
- selectionTextShadow->blur,
- selectionTextShadow->color);
- font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s,
- str->l, s->m_start, s->m_len,
- s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered(), sPos, ePos);
- if (selectionTextShadow)
- p->clearShadow();
- }
- }
- }
-
- // paint decorations
-
- if (d != TDNONE && i.phase != PaintActionSelection &&
- style()->htmlHacks()) {
- p->setPen(_style->color());
- s->paintDecoration(p, tx, ty, d);
- }
-
- // Draw any doc markers that touch this run
- // Note s->end() points at the last char, not one past it like endOffset and ranges do
-
- if (i.phase != PaintActionSelection) {
- for ( ; markerIt != markers.end(); markerIt++) {
- DocumentMarker marker = *markerIt;
-
- if (marker.endOffset <= s->start()) {
- // marker is completely before this run. This might be a marker that sits before the
- // first run we draw, or markers that were within runs we skipped due to truncation.
- continue;
- }
-
- if (marker.startOffset <= s->end()) {
- // marker intersects this run. Paint it.
- s->paintMarker(p, tx, ty, marker);
- if (marker.endOffset > s->end()+1) {
- // marker also runs into the next run. Bail now, no more marker advancement.
- break;
- }
- } else {
- // marker is completely after this run, bail. A later run will paint it.
- break;
- }
- }
- }
-
- if (setShadow)
- p->clearShadow();
-
-#ifdef BIDI_DEBUG
- {
- int h = lineHeight( false ) + paddingTop() + paddingBottom() + borderTop() + borderBottom();
- QColor c2 = QColor("#0000ff");
- drawBorder(p, tx, ty, tx+1, ty + h,
- RenderObject::BSLeft, c2, c2, SOLID, 1, 1);
- drawBorder(p, tx + s->m_width, ty, tx + s->m_width + 1, ty + h,
- RenderObject::BSRight, c2, c2, SOLID, 1, 1);
- }
-#endif
- } while (((s = s->nextTextBox()) != 0) && s->checkVerticalPoint(i.r.y(), ty, i.r.height()));
-#else
-#error This file no longer works without Apple changes
-#endif
-}
-
#ifdef APPLE_CHANGES
bool RenderText::allAscii() const
QRect selectionRect(int absx, int absy, int startPos, int endPos);
bool isSelected(int startPos, int endPos) const;
+ void selectionStartEnd(int& sPos, int& ePos);
+ virtual void paint(RenderObject::PaintInfo& i, int tx, int ty);
+ virtual bool nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty);
+
RenderText* textObject();
virtual void deleteLine(RenderArena* arena);
virtual bool isText() const { return m_treatAsText; }
void setIsText(bool b) { m_treatAsText = b; }
- void paintDecoration( QPainter *pt, int _tx, int _ty, int decoration);
- void paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos);
-#if APPLE_CHANGES
- void paintMarkedTextBackground(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos);
-#endif
- void paintMarker(QPainter *pt, int _tx, int _ty, DOM::DocumentMarker marker);
+ void paintDecoration(QPainter* p, int _tx, int _ty, int decoration);
+ void paintSelection(QPainter* p, int tx, int ty, RenderStyle* style, const Font* font);
+ void paintMarkedTextBackground(QPainter* p, int tx, int ty, RenderStyle* style, const Font* font, int startPos, int endPos);
+ void paintMarker(QPainter* p, int _tx, int _ty, DOM::DocumentMarker marker);
virtual long caretMinOffset() const;
virtual long caretMaxOffset() const;
virtual const char *renderName() const { return "RenderText"; }
virtual void setStyle(RenderStyle *style);
-
- virtual void paint(PaintInfo& i, int tx, int ty);
void extractTextBox(InlineTextBox* textBox);
void attachTextBox(InlineTextBox* textBox);
virtual InlineBox* createInlineBox(bool,bool, bool isOnlyRun = false);
virtual void dirtyLineBoxes(bool fullLayout, bool isRootInlineBox = false);
- virtual void layout() {assert(false);}
+ virtual void paint(PaintInfo& i, int tx, int ty) { assert(false); }
+ virtual void layout() { assert(false); }
virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
- HitTestAction hitTestAction = HitTestAll, bool inside=false);
+ HitTestAction hitTestAction) { assert(false); return false; }
virtual void absoluteRects(QValueList<QRect>& rects, int _tx, int _ty);
}
khtml::RenderObject::NodeInfo renderInfo(true, false);
- doc->renderer()->layer()->nodeAtPoint(renderInfo, m_clientX, m_clientY);
+ doc->renderer()->layer()->hitTest(renderInfo, m_clientX, m_clientY);
NodeImpl *node = renderInfo.innerNonSharedNode();
while (node && !node->renderer()) {
if ( m_render ) {
assert(m_render->isCanvas());
RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
- bool isInside = m_render->layer()->nodeAtPoint(renderInfo, _x, _y);
+ bool isInside = m_render->layer()->hitTest(renderInfo, _x, _y);
ev->innerNode = renderInfo.innerNode();
if (renderInfo.URLElement()) {
return self;
RenderObject::NodeInfo nodeInfo(true, true);
- m_renderer->layer()->nodeAtPoint(nodeInfo, (int)point.x, (int)point.y);
+ m_renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
if (!nodeInfo.innerNode())
return self;
RenderObject* obj = nodeInfo.innerNode()->renderer();
NSPoint point = [d->m_view->getDocumentView() convertPoint:[event locationInWindow] fromView:nil];
RenderObject::NodeInfo nodeInfo(true, true);
- r->layer()->nodeAtPoint(nodeInfo, (int)point.x, (int)point.y);
+ r->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
NodeImpl *node = nodeInfo.innerNode();
if (node == 0) {
int mouseDownX, mouseDownY;
d->m_view->viewportToContents((int)loc.x, (int)loc.y, mouseDownX, mouseDownY);
RenderObject::NodeInfo nodeInfo(true, false);
- renderer()->layer()->nodeAtPoint(nodeInfo, mouseDownX, mouseDownY);
+ renderer()->layer()->hitTest(nodeInfo, mouseDownX, mouseDownY);
bool srcIsDHTML;
Node possibleSrc = nodeInfo.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, mouseDownX, mouseDownY, srcIsDHTML);
return !possibleSrc.isNull();
if (_mouseDownMayStartDrag && _dragSrc.isNull()) {
// try to find an element that wants to be dragged
RenderObject::NodeInfo nodeInfo(true, false);
- renderer()->layer()->nodeAtPoint(nodeInfo, _mouseDownX, _mouseDownY);
+ renderer()->layer()->hitTest(nodeInfo, _mouseDownX, _mouseDownY);
_dragSrc = nodeInfo.innerNode()->renderer()->draggableNode(_dragSrcMayBeDHTML, _dragSrcMayBeUA, _mouseDownX, _mouseDownY, _dragSrcIsDHTML);
if (_dragSrc.isNull()) {
_mouseDownMayStartDrag = false; // no element is draggable
return nil;
}
RenderObject::NodeInfo nodeInfo(true, true);
- renderer->layer()->nodeAtPoint(nodeInfo, (int)point.x, (int)point.y);
+ renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
NSMutableDictionary *element = [NSMutableDictionary dictionary];
[element setObject:[NSNumber numberWithBool:_part->isPointInsideSelection((int)point.x, (int)point.y)]
}
RenderObject::NodeInfo nodeInfo(true, true);
- renderer->layer()->nodeAtPoint(nodeInfo, (int)point.x, (int)point.y);
+ renderer->layer()->hitTest(nodeInfo, (int)point.x, (int)point.y);
NodeImpl *node = nodeInfo.innerNode();
if (!node->renderer())
return Position();