IntPoint RenderDataGrid::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const { RenderView* view = this->view(); if (!view) return scrollbarPoint; IntPoint point = scrollbarPoint; int scrollbarLeft = width() - borderRight() - scrollbar->width(); int scrollbarTop = borderTop(); point.move(scrollbarLeft, scrollbarTop); return view->frameView()->convertFromRenderer(this, point); }
RenderObject* RenderTextControlMultiLine::layoutSpecialExcludedChild(bool relayoutChildren) { RenderObject* placeholderRenderer = RenderTextControl::layoutSpecialExcludedChild(relayoutChildren); if (!placeholderRenderer) return 0; if (!placeholderRenderer->isBox()) return placeholderRenderer; RenderBox* placeholderBox = toRenderBox(placeholderRenderer); placeholderBox->style()->setLogicalWidth(Length(contentLogicalWidth() - placeholderBox->borderAndPaddingLogicalWidth(), Fixed)); placeholderBox->layoutIfNeeded(); placeholderBox->setX(borderLeft() + paddingLeft()); placeholderBox->setY(borderTop() + paddingTop()); return placeholderRenderer; }
void RenderFrameBase::layoutWithFlattening(bool hasFixedWidth, bool hasFixedHeight) { FrameView* childFrameView = toFrameView(widget()); RenderView* childRoot = childFrameView ? childFrameView->frame()->contentRenderer() : 0; if (!childRoot || !shouldExpandFrame(width(), height(), hasFixedWidth, hasFixedHeight)) { updateWidgetPosition(); if (childFrameView) childFrameView->layout(); setNeedsLayout(false); return; } // need to update to calculate min/max correctly updateWidgetPosition(); // if scrollbars are off, and the width or height are fixed // we obey them and do not expand. With frame flattening // no subframe much ever become scrollable. HTMLFrameElementBase* element = static_cast<HTMLFrameElementBase*>(node()); bool isScrollable = element->scrollingMode() != ScrollbarAlwaysOff; // consider iframe inset border int hBorder = borderLeft() + borderRight(); int vBorder = borderTop() + borderBottom(); // make sure minimum preferred width is enforced if (isScrollable || !hasFixedWidth) { setWidth(max(width(), childRoot->minPreferredLogicalWidth() + hBorder)); // update again to pass the new width to the child frame updateWidgetPosition(); childFrameView->layout(); } // expand the frame by setting frame height = content height if (isScrollable || !hasFixedHeight || childRoot->isFrameSet()) setHeight(max<LayoutUnit>(height(), childFrameView->contentsHeight() + vBorder)); if (isScrollable || !hasFixedWidth || childRoot->isFrameSet()) setWidth(max<LayoutUnit>(width(), childFrameView->contentsWidth() + hBorder)); updateWidgetPosition(); ASSERT(!childFrameView->layoutPending()); ASSERT(!childRoot->needsLayout()); ASSERT(!childRoot->firstChild() || !childRoot->firstChild()->firstChild() || !childRoot->firstChild()->firstChild()->needsLayout()); setNeedsLayout(false); }
void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, adjustedPaintOffset); return; } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && hasOutline()) paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size())); if (paintInfo.phase != PaintPhaseForeground) return; if (style().hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) return; // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context().save(); FloatRoundedRect roundedInnerRect = FloatRoundedRect(style().getRoundedInnerBorderFor(borderRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true)); clipRoundedInnerRect(paintInfo.context(), borderRect, roundedInnerRect); } if (m_widget) paintContents(paintInfo, paintOffset); if (style().hasBorderRadius()) paintInfo.context().restore(); // Paint a partially transparent wash over selected widgets. if (isSelected() && !document().printing()) { // FIXME: selectionRect() is in absolute, not painting coordinates. paintInfo.context().fillRect(snappedIntRect(selectionRect()), selectionBackgroundColor(), style().colorSpace()); } if (hasLayer() && layer()->canResize()) layer()->paintResizer(paintInfo.context(), roundedIntPoint(adjustedPaintOffset), paintInfo.rect); }
void RenderFrameBase::peformLayoutWithFlattening(bool hasFixedWidth, bool hasFixedHeight) { if (!childRenderView()) return; if (!shouldExpandFrame(width(), height(), hasFixedWidth, hasFixedHeight)) { if (updateWidgetPosition() == ChildWidgetState::Destroyed) return; childView()->layout(); return; } // need to update to calculate min/max correctly if (updateWidgetPosition() == ChildWidgetState::Destroyed) return; // if scrollbars are off, and the width or height are fixed // we obey them and do not expand. With frame flattening // no subframe much ever become scrollable. bool isScrollable = frameOwnerElement().scrollingMode() != ScrollbarAlwaysOff; // consider iframe inset border int hBorder = borderLeft() + borderRight(); int vBorder = borderTop() + borderBottom(); // make sure minimum preferred width is enforced if (isScrollable || !hasFixedWidth) { ASSERT(childRenderView()); setWidth(std::max(width(), childRenderView()->minPreferredLogicalWidth() + hBorder)); // update again to pass the new width to the child frame if (updateWidgetPosition() == ChildWidgetState::Destroyed) return; childView()->layout(); } ASSERT(childView()); // expand the frame by setting frame height = content height if (isScrollable || !hasFixedHeight || childRenderView()->isFrameSet()) setHeight(std::max<LayoutUnit>(height(), childView()->contentsHeight() + vBorder)); if (isScrollable || !hasFixedWidth || childRenderView()->isFrameSet()) setWidth(std::max<LayoutUnit>(width(), childView()->contentsWidth() + hBorder)); if (updateWidgetPosition() == ChildWidgetState::Destroyed) return; ASSERT(!childView()->layoutPending()); ASSERT(!childRenderView()->needsLayout()); ASSERT(!childRenderView()->firstChild() || !childRenderView()->firstChild()->firstChildSlow() || !childRenderView()->firstChild()->firstChildSlow()->needsLayout()); }
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Vector<RenderBox*>& layers) { if (!shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasBoxDecorationBackground()) paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size()); if (style()->outlineWidth()) paintOutline(paintInfo, paintRect); bool completelyClippedOut = false; if (style()->hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(paintRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true); clipRoundedInnerRect(paintInfo.context, paintRect, roundedInnerRect); } } if (!completelyClippedOut) { paintReplaced(paintInfo, adjustedPaintOffset); if (style()->hasBorderRadius()) paintInfo.context->restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (selectionState() != SelectionNone) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); paintInfo.context->fillRect(pixelSnappedIntRect(selectionPaintingRect), selectionBackgroundColor()); } }
void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) { if (!shouldPaint(paintInfo, tx, ty)) return; tx += x(); ty += y(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, tx, ty); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, tx, ty); return; } if (!m_view || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE) return; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true); #endif if (m_widget) { // Move the widget if necessary. We normally move and resize widgets during layout, but sometimes // widgets can move without layout occurring (most notably when you scroll a document that // contains fixed positioned elements). m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop()); // Tell the widget to paint now. This is the only time the widget is allowed // to paint itself. That way it will composite properly with z-indexed layers. m_widget->paint(paintInfo.context, paintInfo.rect); } // Paint a partially transparent wash over selected widgets. if (isSelected() && !document()->printing()) { // FIXME: selectionRect() is in absolute, not painting coordinates. paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor()); } }
void RenderMedia::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; LayoutSize oldSize = contentBoxRect().size(); RenderImage::layout(); RenderBox* controlsRenderer = toRenderBox(m_children.firstChild()); if (!controlsRenderer) return; bool controlsNeedLayout = controlsRenderer->needsLayout(); // If the region chain has changed we also need to relayout the controls to update the region box info. // FIXME: We can do better once we compute region box info for RenderReplaced, not only for RenderBlock. const RenderFlowThread* flowThread = flowThreadContainingBlock(); if (flowThread && !controlsNeedLayout) { if (flowThread->pageLogicalSizeChanged()) controlsNeedLayout = true; } LayoutSize newSize = contentBoxRect().size(); if (newSize == oldSize && !controlsNeedLayout) return; // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient, // and this method will be called many times per second during playback, use a LayoutStateMaintainer: LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); controlsRenderer->setNeedsLayout(true, MarkOnlyThis); controlsRenderer->layout(); setChildNeedsLayout(false); statePusher.pop(); }
bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameContent()) return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); FrameView* childFrameView = toFrameView(widget()); RenderView* childRoot = childFrameView->renderView(); if (childRoot) { LayoutPoint adjustedLocation = accumulatedOffset + location(); LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - childFrameView->scrollOffset(); HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset); HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest); HitTestResult childFrameResult(newHitTestLocation); bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, childFrameResult); if (newHitTestLocation.isRectBasedTest()) result.append(childFrameResult); else if (isInsideChildFrame) result = childFrameResult; if (isInsideChildFrame) return true; if (request.allowsFrameScrollbars()) { // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls, // so we need to test ScrollView scrollbars separately here. // FIXME: Consider if this test could be done unconditionally. Scrollbar* frameScrollbar = childFrameView->scrollbarAtPoint(newHitTestLocation.roundedPoint()); if (frameScrollbar) result.setScrollbar(frameScrollbar); } } return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); }
// Hit Testing bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!isValid() || action != HitTestForeground) return false; LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); boundsRect.moveBy(accumulatedOffset); if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) { if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft() + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop()))) return true; } return false; }
VisiblePosition RenderContainer::positionForCoordinates(int x, int y) { // no children...return this render object's element, if there is one, and offset 0 if (!m_firstChild) return VisiblePosition(element(), 0, DOWNSTREAM); if (isTable() && element()) { int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft(); int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom(); if (x < 0 || x > right || y < 0 || y > bottom) { if (x <= right / 2) return VisiblePosition(Position(element(), 0)); else return VisiblePosition(Position(element(), maxDeepOffset(element()))); } } // Pass off to the closest child. int minDist = INT_MAX; RenderObject* closestRenderer = 0; int newX = x; int newY = y; if (isTableRow()) { newX += xPos(); newY += yPos(); } for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) { if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow() || renderer->style()->visibility() != VISIBLE) continue; int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos()); int bottom = top + renderer->contentHeight(); int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos()); int right = left + renderer->contentWidth(); if (x <= right && x >= left && y <= top && y >= bottom) { if (renderer->isTableRow()) return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos()); return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos()); } // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces // and use a different compare depending on which piece (x, y) is in. IntPoint cmp; if (x > right) { if (y < top) cmp = IntPoint(right, top); else if (y > bottom) cmp = IntPoint(right, bottom); else cmp = IntPoint(right, y); } else if (x < left) { if (y < top) cmp = IntPoint(left, top); else if (y > bottom) cmp = IntPoint(left, bottom); else cmp = IntPoint(left, y); } else { if (y < top) cmp = IntPoint(x, top); else cmp = IntPoint(x, bottom); } int x1minusx2 = cmp.x() - x; int y1minusy2 = cmp.y() - y; int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2; if (dist < minDist) { closestRenderer = renderer; minDist = dist; } } if (closestRenderer) return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos()); return VisiblePosition(element(), 0, DOWNSTREAM); }
void RenderRegion::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // Delegate painting of content in region to RenderFlowThread. if (!m_flowThread || !isValid()) return; m_flowThread->paintIntoRegion(paintInfo, this, LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); }
void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (style()->visibility() != VISIBLE) return; RenderBlock::paintObject(paintInfo, paintOffset); // Delegate painting of content in region to RenderFlowThread. // RenderFlowThread is a self painting layer (being a positioned object) who is painting its children, the collected objects. // Since we do not want to paint the flow thread content multiple times (for each painting phase of the region object), // we allow the flow thread painting only for the selection and the foreground phase. if (!isValid() || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) return; setRegionObjectsRegionStyle(); m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); restoreRegionObjectsOriginalStyle(); }
void Cell::borderTopBottom(bool show) { borderTop(show); borderBottom(show); }
void RenderRegion::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // Delegate painting of content in region to RenderFlowThread. if (!m_flowThread || !isValid()) return; #ifndef NDEBUG m_insideRegionPaint = true; #endif setRegionBoxesRegionStyle(); m_flowThread->paintIntoRegion(paintInfo, this, LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); restoreRegionBoxesOriginalStyle(); #ifndef NDEBUG m_insideRegionPaint = false; #endif }
void RenderSVGContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) { if (paintInfo.context->paintingDisabled()) return; // This should only exist for <svg> renderers if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) paintOutline(paintInfo.context, parentX, parentY, width(), height(), style()); if (paintInfo.phase != PaintPhaseForeground || !drawsContents()) return; const SVGRenderStyle* svgStyle = style()->svgStyle(); AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter())); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) SVGResourceFilter* filter = getFilterById(document(), filterId); #endif if (!firstChild() #if ENABLE(SVG_EXPERIMENTAL_FEATURES) && !filter #endif ) return; // Spec: groups w/o children still may render filter content. paintInfo.context->save(); if (!parent()->isSVGContainer()) { // Translate from parent offsets (html renderers) to a relative transform (svg renderers) IntPoint origin; origin.move(parentX, parentY); origin.move(m_x, m_y); origin.move(borderLeft(), borderTop()); origin.move(paddingLeft(), paddingTop()); if (origin.x() || origin.y()) { paintInfo.context->concatCTM(AffineTransform().translate(origin.x(), origin.y())); paintInfo.rect.move(-origin.x(), -origin.y()); } parentX = parentY = 0; SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); paintInfo.context->concatCTM(AffineTransform().scale(svg->currentScale())); } else { // Only the root <svg> element should need any translations using the HTML/CSS system // parentX, parentY are also non-zero for first-level kids of these // CSS-transformed <svg> root-elements (due to RenderBox::paint) for any other element // they should be 0. m_x, m_y should always be 0 for non-root svg containers ASSERT(m_x == 0); ASSERT(m_y == 0); } if (!viewport().isEmpty()) { if (style()->overflowX() != OVISIBLE) paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping paintInfo.context->concatCTM(AffineTransform().translate(viewport().x(), viewport().y())); } if (!localTransform().isIdentity()) paintInfo.context->concatCTM(localTransform()); if (!parent()->isSVGContainer()) { SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); paintInfo.context->concatCTM(AffineTransform().translate(svg->currentTranslate().x(), svg->currentTranslate().y())); } FloatRect strokeBBox = relativeBBox(true); SVGElement* svgElement = static_cast<SVGElement*>(element()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); AtomicString clipperId(SVGURIReference::getTarget(svgStyle->clipPath())); AtomicString maskerId(SVGURIReference::getTarget(svgStyle->maskElement())); SVGResourceClipper* clipper = getClipperById(document(), clipperId); SVGResourceMasker* masker = getMaskerById(document(), maskerId); if (clipper) { clipper->addClient(styledElement); clipper->applyClip(paintInfo.context, strokeBBox); } else if (!clipperId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement); if (masker) { masker->addClient(styledElement); masker->applyMask(paintInfo.context, strokeBBox); } else if (!maskerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); float opacity = style()->opacity(); if (opacity < 1.0f) { paintInfo.context->clip(enclosingIntRect(strokeBBox)); paintInfo.context->beginTransparencyLayer(opacity); } #if ENABLE(SVG_EXPERIMENTAL_FEATURES) if (filter) filter->prepareFilter(paintInfo.context, strokeBBox); else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif if (!viewBox().isEmpty()) paintInfo.context->concatCTM(viewportTransform()); RenderContainer::paint(paintInfo, 0, 0); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) if (filter) filter->applyFilter(paintInfo.context, strokeBBox); #endif if (opacity < 1.0f) paintInfo.context->endTransparencyLayer(); paintInfo.context->restore(); }
LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset) { ASSERT(!slowFirstChild()); // FIXME: This does not take into account either :first-line or :first-letter // However, as soon as some content is entered, the line boxes will be // constructed and this kludge is not called any more. So only the caret size // of an empty :first-line'd block is wrong. I think we can live with that. RenderStyle* currentStyle = firstLineStyle(); enum CaretAlignment { alignLeft, alignRight, alignCenter }; CaretAlignment alignment = alignLeft; switch (currentStyle->textAlign()) { case LEFT: case WEBKIT_LEFT: break; case CENTER: case WEBKIT_CENTER: alignment = alignCenter; break; case RIGHT: case WEBKIT_RIGHT: alignment = alignRight; break; case JUSTIFY: case TASTART: if (!currentStyle->isLeftToRightDirection()) alignment = alignRight; break; case TAEND: if (currentStyle->isLeftToRightDirection()) alignment = alignRight; break; } LayoutUnit x = borderLeft() + paddingLeft(); LayoutUnit maxX = width - borderRight() - paddingRight(); switch (alignment) { case alignLeft: if (currentStyle->isLeftToRightDirection()) x += textIndentOffset; break; case alignCenter: x = (x + maxX) / 2; if (currentStyle->isLeftToRightDirection()) x += textIndentOffset / 2; else x -= textIndentOffset / 2; break; case alignRight: x = maxX - caretWidth; if (!currentStyle->isLeftToRightDirection()) x -= textIndentOffset; break; } x = std::min(x, std::max<LayoutUnit>(maxX - caretWidth, 0)); LayoutUnit height = style()->fontMetrics().height(); LayoutUnit verticalSpace = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes) - height; LayoutUnit y = paddingTop() + borderTop() + (verticalSpace / 2); return currentStyle->isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth, height) : LayoutRect(y, x, height, caretWidth); }
void RenderRadio::paintObject(PaintInfo& i, int _tx, int _ty) { ASSERT(node()); Element* element = static_cast<Element*>(node()); InputElement* inputElement = toInputElement(element); bool isEnabled = element->isEnabledFormControl(); bool isChecked = inputElement->isChecked(); i.context->save(); RefPtr<Image> image = Image::loadPlatformResource( "radioButtonStates" ).get(); IntPoint destPt( _tx, _ty ); IntRect srcRect( 0, 0, 14, 16 ); if (isEnabled) { if (node()->active()) { if (isChecked) { srcRect.move( 75, 0 ); } else { srcRect.move( 60, 0 ); } } else if (node()->hovered()) { if (isChecked) { srcRect.move( 45, 0 ); } else { srcRect.move( 30, 0 ); } } else { if (isChecked) { srcRect.move( 15, 0 ); } else { } } } else { if (isChecked) { srcRect.move( 105, 0 ); } else { srcRect.move( 90, 0 ); } } i.context->drawImage( image.get(), DeviceColorSpace, destPt, srcRect ); // draw the focus ring. // if (node()->focused()) { IntRect focusRingSrcRect( 120, 0, 15, 17 ); i.context->drawImage( image.get(), DeviceColorSpace, destPt, focusRingSrcRect ); } #if 0 // this is the old "moveto - lineto" drawing code IntRect checkRect(_tx + borderLeft() , _ty + borderTop() , width() - borderLeft() - borderRight() , height() - borderBottom() - borderTop()); Color fillColor(0xff, 0xff, 0xff, 0x00); Color rectColor(0x18, 0x52, 0x84); Color checkColor(0x21, 0xa5, 0x21); if (!node()->isEnabled()) { rectColor = Color(0xce, 0xce, 0xdb); checkColor = Color(0xce, 0xce, 0xdb); } i.context->setStrokeThickness(1); i.context->setStrokeStyle(SolidStroke); i.context->setStrokeColor(rectColor); i.context->setFillColor(fillColor); i.context->drawEllipse(checkRect); if(node()->isEnabled() && node()->hovered()) { i.context->setStrokeColor(Color(0xff, 0xb5, 0x31)); IntRect hoverRect = checkRect; hoverRect.inflateX(-1); hoverRect.inflateY(-1); i.context->drawEllipse( hoverRect ); hoverRect.inflateX(-1); hoverRect.inflateY(-1); i.context->drawEllipse( hoverRect ); } if (isChecked) { i.context->setStrokeThickness(2); i.context->setStrokeColor(checkColor); i.context->setFillColor(checkColor); IntRect fillRect = checkRect; fillRect.inflateX(-2); fillRect.inflateY(-2); i.context->drawEllipse(fillRect); } #endif i.context->restore(); }
IntSize RenderSVGRoot::borderOriginToContentBox() const { return IntSize(borderLeft() + paddingLeft(), borderTop() + paddingTop()); }
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); if (!shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, adjustedPaintOffset); return; } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size()); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth()) paintOutline(paintInfo, paintRect); if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren()) return; if (!paintInfo.shouldPaintWithinRoot(this)) return; bool drawSelectionTint = selectionState() != SelectionNone && !document()->printing(); if (paintInfo.phase == PaintPhaseSelection) { if (selectionState() == SelectionNone) return; drawSelectionTint = false; } bool completelyClippedOut = false; if (style()->hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context->save(); RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(paintRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true); clipRoundedInnerRect(paintInfo.context, paintRect, roundedInnerRect); } } if (!completelyClippedOut) { paintReplaced(paintInfo, adjustedPaintOffset); if (style()->hasBorderRadius()) paintInfo.context->restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (drawSelectionTint) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); paintInfo.context->fillRect(pixelSnappedIntRect(selectionPaintingRect), selectionBackgroundColor()); } }
// Hit Testing bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!isValid()) return false; LayoutPoint adjustedLocation = accumulatedOffset + location(); // 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). // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect. LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); boundsRect.moveBy(adjustedLocation); if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) { // Check the contents of the RenderFlowThread. if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop()))) return true; updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); if (!result.addNodeToRectBasedTestResult(generatingNode(), request, locationInContainer, boundsRect)) return true; } return false; }
void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.context->paintingDisabled()) return; RenderMultiColumnFlowThread* flowThread = toRenderBlockFlow(parent())->multiColumnFlowThread(); const RenderStyle& blockStyle = parent()->style(); const Color& ruleColor = blockStyle.visitedDependentColor(CSSPropertyWebkitColumnRuleColor); bool ruleTransparent = blockStyle.columnRuleIsTransparent(); EBorderStyle ruleStyle = blockStyle.columnRuleStyle(); LayoutUnit ruleThickness = blockStyle.columnRuleWidth(); LayoutUnit colGap = columnGap(); bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; if (!renderRule) return; unsigned colCount = columnCount(); if (colCount <= 1) return; bool antialias = shouldAntialiasLines(paintInfo.context); if (flowThread->progressionIsInline()) { bool leftToRight = style().isLeftToRightDirection() ^ flowThread->progressionIsReversed(); LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth(); LayoutUnit ruleAdd = logicalLeftOffsetForContent(); LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth(); LayoutUnit inlineDirectionSize = computedColumnWidth(); BoxSide boxSide = isHorizontalWritingMode() ? leftToRight ? BSLeft : BSRight : leftToRight ? BSTop : BSBottom; for (unsigned i = 0; i < colCount; i++) { // Move to the next position. if (leftToRight) { ruleLogicalLeft += inlineDirectionSize + colGap / 2; currLogicalLeftOffset += inlineDirectionSize + colGap; } else { ruleLogicalLeft -= (inlineDirectionSize + colGap / 2); currLogicalLeftOffset -= (inlineDirectionSize + colGap); } // Now paint the column rule. if (i < colCount - 1) { LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft(); LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth(); LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd; LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness; IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom); drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias); } ruleLogicalLeft = currLogicalLeftOffset; } } else { bool topToBottom = !style().isFlippedBlocksWritingMode() ^ flowThread->progressionIsReversed(); LayoutUnit ruleLeft = isHorizontalWritingMode() ? LayoutUnit() : colGap / 2 - colGap - ruleThickness / 2; LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness; LayoutUnit ruleTop = isHorizontalWritingMode() ? colGap / 2 - colGap - ruleThickness / 2 : LayoutUnit(); LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight(); LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight); if (!topToBottom) { if (isHorizontalWritingMode()) ruleRect.setY(height() - ruleRect.maxY()); else ruleRect.setX(width() - ruleRect.maxX()); } ruleRect.moveBy(paintOffset); BoxSide boxSide = isHorizontalWritingMode() ? topToBottom ? BSTop : BSBottom : topToBottom ? BSLeft : BSRight; LayoutSize step(0, topToBottom ? computedColumnHeight() + colGap : -(computedColumnHeight() + colGap)); if (!isHorizontalWritingMode()) step = step.transposedSize(); for (unsigned i = 1; i < colCount; i++) { ruleRect.move(step); IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect); drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias); } } }
// Hit Testing bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!isValid()) return false; LayoutPoint adjustedLocation = accumulatedOffset + location(); // 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). LayoutRect boundsRect(adjustedLocation, size()); if (visibleToHitTesting() && action == HitTestForeground && boundsRect.intersects(result.rectForPoint(pointInContainer))) { // Check the contents of the RenderFlowThread. if (m_flowThread && m_flowThread->hitTestRegion(this, request, result, pointInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop()))) return true; updateHitTestResult(result, pointInContainer - toLayoutSize(adjustedLocation)); if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) return true; } return false; }
void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (style()->visibility() != VISIBLE) return; RenderBlock::paintObject(paintInfo, paintOffset); if (!isValid()) return; // We do not want to paint a region's contents multiple times (for each paint phase of the region object). // Thus, we only paint the region's contents in certain phases. if (!shouldPaintRegionContentsInPhase(paintInfo.phase)) return; // Delegate the painting of a region's contents to RenderFlowThread. // RenderFlowThread is a self painting layer because it's a positioned object. // RenderFlowThread paints its children, the collected objects. setRegionObjectsRegionStyle(); m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); restoreRegionObjectsOriginalStyle(); }
void RenderReplaced::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!shouldPaint(paintInfo, paintOffset)) return; #ifndef NDEBUG SetLayoutNeededForbiddenScope scope(this); #endif LayoutPoint adjustedPaintOffset = paintOffset + location(); if (hasVisibleBoxDecorations() && paintInfo.phase == PaintPhaseForeground) paintBoxDecorations(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, adjustedPaintOffset); return; } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, size()); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style().outlineWidth()) paintOutline(paintInfo, paintRect); if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && !canHaveChildren()) return; if (!paintInfo.shouldPaintWithinRoot(*this)) return; bool drawSelectionTint = shouldDrawSelectionTint(); if (paintInfo.phase == PaintPhaseSelection) { if (selectionState() == SelectionNone) return; drawSelectionTint = false; } bool completelyClippedOut = false; if (style().hasBorderRadius()) { LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); if (borderRect.isEmpty()) completelyClippedOut = true; else { // Push a clip if we have a border radius, since we want to round the foreground content that gets painted. paintInfo.context().save(); FloatRoundedRect roundedInnerRect = FloatRoundedRect(style().getRoundedInnerBorderFor(paintRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true)); clipRoundedInnerRect(paintInfo.context(), paintRect, roundedInnerRect); } } if (!completelyClippedOut) { paintReplaced(paintInfo, adjustedPaintOffset); if (style().hasBorderRadius()) paintInfo.context().restore(); } // The selection tint never gets clipped by border-radius rounding, since we want it to run right up to the edges of // surrounding content. if (drawSelectionTint) { LayoutRect selectionPaintingRect = localSelectionRect(); selectionPaintingRect.moveBy(adjustedPaintOffset); paintInfo.context().fillRect(snappedIntRect(selectionPaintingRect), selectionBackgroundColor()); } }
void RenderRegion::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // Delegate painting of content in region to RenderFlowThread. if (!m_flowThread || !isValid()) return; if (Frame* frame = this->frame()) { if (Page* page = frame->page()) page->addRelevantRepaintedObject(this, paintInfo.rect); } setRegionBoxesRegionStyle(); m_flowThread->paintIntoRegion(paintInfo, this, LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); restoreRegionBoxesOriginalStyle(); }