void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { MediaPlayer* mediaPlayer = videoElement().player(); bool displayingPoster = videoElement().shouldDisplayPosterImage(); Page* page = frame().page(); if (!displayingPoster && !mediaPlayer) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } LayoutRect rect = videoBox(); if (rect.isEmpty()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } rect.moveBy(paintOffset); if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, rect); LayoutRect contentRect = contentBoxRect(); contentRect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context(); bool clip = !contentRect.contains(rect); GraphicsContextStateSaver stateSaver(context, clip); if (clip) context.clip(contentRect); if (displayingPoster) paintIntoRect(context, rect); else if (!videoElement().isFullscreen() || !mediaPlayer->supportsAcceleratedRendering()) { if (view().frameView().paintBehavior() & PaintBehaviorFlattenCompositingLayers) mediaPlayer->paintCurrentFrameInContext(context, rect); else mediaPlayer->paint(context, rect); } }
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()); 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()); } }
static void adjustBubblePosition(const LayoutRect& hostRect, HTMLElement* bubble) { ASSERT(bubble); if (hostRect.isEmpty()) return; double hostX = hostRect.x(); double hostY = hostRect.y(); if (RenderBox* container = bubble->renderer()->containingBlock()) { FloatPoint containerLocation = container->localToAbsolute(); hostX -= containerLocation.x() + container->borderLeft(); hostY -= containerLocation.y() + container->borderTop(); } bubble->setInlineStyleProperty(CSSPropertyTop, hostY + hostRect.height(), CSSPrimitiveValue::CSS_PX); // The 'left' value of ::-webkit-validation-bubble-arrow. const int bubbleArrowTopOffset = 32; double bubbleX = hostX; if (hostRect.width() / 2 < bubbleArrowTopOffset) bubbleX = max(hostX + hostRect.width() / 2 - bubbleArrowTopOffset, 0.0); bubble->setInlineStyleProperty(CSSPropertyLeft, bubbleX, CSSPrimitiveValue::CSS_PX); }
LayoutRect AccessibilityObject::boundingBoxForQuads(RenderObject* obj, const Vector<FloatQuad>& quads) { ASSERT(obj); if (!obj) return LayoutRect(); size_t count = quads.size(); if (!count) return LayoutRect(); LayoutRect result; for (size_t i = 0; i < count; ++i) { LayoutRect r = quads[i].enclosingBoundingBox(); if (!r.isEmpty()) { if (obj->style()->hasAppearance()) obj->theme()->adjustRepaintRect(obj, r); result.unite(r); } } return result; }
void BlockFlowPainter::paintSelection(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase == PaintPhaseForeground); if (!m_layoutBlockFlow.shouldPaintSelectionGaps()) return; LayoutUnit lastTop = 0; LayoutUnit lastLeft = m_layoutBlockFlow.logicalLeftSelectionOffset(&m_layoutBlockFlow, lastTop); LayoutUnit lastRight = m_layoutBlockFlow.logicalRightSelectionOffset(&m_layoutBlockFlow, lastTop); LayoutRect bounds = m_layoutBlockFlow.visualOverflowRect(); bounds.moveBy(paintOffset); // Only create a DrawingRecorder and ClipScope if skipRecording is false. This logic is needed // because selectionGaps(...) needs to be called even when we do not record. bool skipRecording = LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, paintOffset); Optional<LayoutObjectDrawingRecorder> drawingRecorder; Optional<ClipScope> clipScope; if (!skipRecording) { drawingRecorder.emplace(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, FloatRect(bounds), paintOffset); clipScope.emplace(paintInfo.context); } LayoutRect gapRectsBounds = m_layoutBlockFlow.selectionGaps(&m_layoutBlockFlow, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, skipRecording ? nullptr : &paintInfo, skipRecording ? nullptr : &(*clipScope)); // TODO(wkorman): Rework below to process paint invalidation rects during layout rather than paint. if (!gapRectsBounds.isEmpty()) { PaintLayer* layer = m_layoutBlockFlow.enclosingLayer(); gapRectsBounds.moveBy(-paintOffset); if (!m_layoutBlockFlow.hasLayer()) { LayoutRect localBounds(gapRectsBounds); m_layoutBlockFlow.flipForWritingMode(localBounds); gapRectsBounds = LayoutRect(m_layoutBlockFlow.localToAncestorQuad(FloatRect(localBounds), layer->layoutObject()).enclosingBoundingBox()); if (layer->layoutObject()->hasOverflowClip()) gapRectsBounds.move(layer->layoutBox()->scrolledContentOffset()); } layer->addBlockSelectionGapsBounds(gapRectsBounds); } }
bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect) { ASSERT(m_haveFilterEffect && renderLayer->filterRenderer()); m_renderLayer = renderLayer; m_repaintRect = dirtyRect; FilterEffectRenderer* filter = renderLayer->filterRenderer(); LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect); if (filterSourceRect.isEmpty()) { // The dirty rect is not in view, just bail out. m_haveFilterEffect = false; return false; } // Get the zoom factor to scale the filterSourceRect input const RenderLayerModelObject* renderer = renderLayer->renderer(); const RenderStyle* style = renderer ? renderer->style() : 0; float zoom = style ? style->effectiveZoom() : 1.0f; AffineTransform absoluteTransform; absoluteTransform.translate(filterBoxRect.x(), filterBoxRect.y()); filter->setAbsoluteTransform(absoluteTransform); filter->setAbsoluteFilterRegion(AffineTransform().scale(zoom).mapRect(filterSourceRect)); filter->setFilterRegion(absoluteTransform.inverse().mapRect(filterSourceRect)); filter->lastEffect()->determineFilterPrimitiveSubregion(); bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect); if (filter->hasFilterThatMovesPixels()) { if (hasUpdatedBackingStore) m_repaintRect = filterSourceRect; else { m_repaintRect.unite(layerRepaintRect); m_repaintRect.intersect(filterSourceRect); } } return true; }
void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { MediaPlayer* mediaPlayer = mediaElement()->player(); bool displayingPoster = videoElement()->shouldDisplayPosterImage(); if (!displayingPoster) { if (!mediaPlayer) return; updatePlayer(); } LayoutRect rect = videoBox(); if (rect.isEmpty()) return; rect.moveBy(paintOffset); if (displayingPoster) paintIntoRect(paintInfo.context, rect); else if (document()->view() && document()->view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) mediaPlayer->paintCurrentFrameInContext(paintInfo.context, rect); else mediaPlayer->paint(paintInfo.context, rect); }
void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const { if (m_caretVisibility == Hidden) return; LayoutRect drawingRect = localCaretRectWithoutUpdate(); drawingRect.moveBy(roundedIntPoint(paintOffset)); LayoutRect caret = intersection(drawingRect, clipRect); if (caret.isEmpty()) return; Color caretColor = Color::black; Element* element; if (node->isElementNode()) element = toElement(node); else element = node->parentElement(); if (element && element->renderer()) caretColor = element->renderer()->resolveColor(CSSPropertyColor); context->fillRect(caret, caretColor); }
void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { MediaPlayer* mediaPlayer = mediaElement()->player(); bool displayingPoster = videoElement()->shouldDisplayPosterImage(); Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); if (!displayingPoster) { if (!mediaPlayer) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } updatePlayer(); } LayoutRect rect = videoBox(); if (rect.isEmpty()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } rect.moveBy(paintOffset); if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, rect); if (displayingPoster) paintIntoRect(paintInfo.context, rect); else if (document()->view() && document()->view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) mediaPlayer->paintCurrentFrameInContext(paintInfo.context, pixelSnappedIntRect(rect)); else mediaPlayer->paint(paintInfo.context, pixelSnappedIntRect(rect)); }
bool RenderEmbeddedObject::isReplacementObscured() const { // Return whether or not the replacement content for blocked plugins is accessible to the user. // Check the opacity of each layer containing the element or its ancestors. float opacity = 1.0; for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) { RenderLayerModelObject* renderer = layer->renderer(); RenderStyle* style = renderer->style(); opacity *= style->opacity(); if (opacity < 0.1) return true; } // Calculate the absolute rect for the blocked plugin replacement text. IntRect absoluteBoundingBox = absoluteBoundingBoxRect(); LayoutPoint absoluteLocation(absoluteBoundingBox.location()); LayoutRect rect = replacementTextRect(absoluteLocation); if (rect.isEmpty()) return true; RenderView* docRenderer = document()->renderView(); ASSERT(docRenderer); if (!docRenderer) return true; HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent); HitTestResult result; HitTestLocation location; LayoutUnit x = rect.x(); LayoutUnit y = rect.y(); LayoutUnit width = rect.width(); LayoutUnit height = rect.height(); // Hit test the center and near the corners of the replacement text to ensure // it is visible and is not masked by other elements. bool hit = false; location = LayoutPoint(x + width / 2, y + height / 2); hit = docRenderer->hitTest(request, location, result); if (!hit || result.innerNode() != node()) return true; location = LayoutPoint(x, y); hit = docRenderer->hitTest(request, location, result); if (!hit || result.innerNode() != node()) return true; location = LayoutPoint(x + width, y); hit = docRenderer->hitTest(request, location, result); if (!hit || result.innerNode() != node()) return true; location = LayoutPoint(x + width, y + height); hit = docRenderer->hitTest(request, location, result); if (!hit || result.innerNode() != node()) return true; location = LayoutPoint(x, y + height); hit = docRenderer->hitTest(request, location, result); if (!hit || result.innerNode() != node()) return true; return false; }
bool RenderEmbeddedObject::isReplacementObscured() const { // Return whether or not the replacement content for blocked plugins is accessible to the user. // Check the opacity of each layer containing the element or its ancestors. float opacity = 1.0; for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) { opacity *= layer->renderer().style().opacity(); if (opacity < 0.1) return true; } // Calculate the absolute rect for the blocked plugin replacement text. IntRect absoluteBoundingBox = absoluteBoundingBoxRect(); LayoutPoint absoluteLocation(absoluteBoundingBox.location()); LayoutRect rect = unavailablePluginIndicatorBounds(absoluteLocation); if (rect.isEmpty()) return true; RenderView* rootRenderView = document().topDocument().renderView(); ASSERT(rootRenderView); if (!rootRenderView) return true; IntRect rootViewRect = view().frameView().convertToRootView(snappedIntRect(rect)); HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent); HitTestResult result; HitTestLocation location; LayoutUnit x = rootViewRect.x(); LayoutUnit y = rootViewRect.y(); LayoutUnit width = rootViewRect.width(); LayoutUnit height = rootViewRect.height(); // Hit test the center and near the corners of the replacement text to ensure // it is visible and is not masked by other elements. bool hit = false; location = LayoutPoint(x + width / 2, y + height / 2); hit = rootRenderView->hitTest(request, location, result); if (!hit || result.innerNode() != &frameOwnerElement()) return true; location = LayoutPoint(x, y); hit = rootRenderView->hitTest(request, location, result); if (!hit || result.innerNode() != &frameOwnerElement()) return true; location = LayoutPoint(x + width, y); hit = rootRenderView->hitTest(request, location, result); if (!hit || result.innerNode() != &frameOwnerElement()) return true; location = LayoutPoint(x + width, y + height); hit = rootRenderView->hitTest(request, location, result); if (!hit || result.innerNode() != &frameOwnerElement()) return true; location = LayoutPoint(x, y + height); hit = rootRenderView->hitTest(request, location, result); if (!hit || result.innerNode() != &frameOwnerElement()) return true; return false; }
bool LayoutRect::intersects(const LayoutRect& other) const { // Checking emptiness handles negative widths as well as zero. return !isEmpty() && !other.isEmpty() && x() < other.maxX() && other.x() < maxX() && y() < other.maxY() && other.y() < maxY(); }
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call void RenderSVGContainer::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) const { LayoutRect paintRectInParent = LayoutRect(localToParentTransform().mapRect(paintInvalidationRectInLocalCoordinates())); if (!paintRectInParent.isEmpty()) rects.append(paintRectInParent); }
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()); } }
// addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call void RenderSVGContainer::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&) { LayoutRect paintRectInParent = enclosingLayoutRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); if (!paintRectInParent.isEmpty()) rects.append(paintRectInParent); }
// This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords void RenderSVGShape::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { LayoutRect rect = LayoutRect(repaintRectInLocalCoordinates()); if (!rect.isEmpty()) rects.append(rect); }
void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, const Color outlineColor) { RenderStyle* styleToUse = m_renderInline.style(); int outlineWidth = styleToUse->outlineWidth(); EBorderStyle outlineStyle = styleToUse->outlineStyle(); bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext); int offset = m_renderInline.style()->outlineOffset(); LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset), LayoutSize(thisline.width() + offset, thisline.height() + offset)); IntRect pixelSnappedBox = pixelSnappedIntRect(box); if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0) return; IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0); IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0); // left edge ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), pixelSnappedBox.x(), pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), BSLeft, outlineColor, outlineStyle, (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), antialias); // right edge ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.maxX(), pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0), BSRight, outlineColor, outlineStyle, (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth), (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth), antialias); // upper edge if (thisline.x() < lastline.x()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - outlineWidth, std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())), pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, outlineWidth, (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, antialias); } if (lastline.maxX() < thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.y() - outlineWidth, pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth, outlineWidth, antialias); } if (thisline.x() == thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - outlineWidth, pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth, antialias); } // lower edge if (thisline.x() < nextline.x()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.maxY(), std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000), pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, outlineWidth, (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, antialias); } if (nextline.maxX() < thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.maxY(), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth, outlineWidth, antialias); } if (thisline.x() == thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.maxY(), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth, antialias); } }
void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, const Color outlineColor) { const ComputedStyle& styleToUse = m_layoutInline.styleRef(); int outlineWidth = styleToUse.outlineWidth(); EBorderStyle outlineStyle = styleToUse.outlineStyle(); bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext); int offset = m_layoutInline.style()->outlineOffset(); LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset), LayoutSize(thisline.width() + offset, thisline.height() + offset)); IntRect pixelSnappedBox = pixelSnappedIntRect(box); if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0) return; // Note that we use IntRect below for working with solely x/width values, simplifying logic at cost of a bit of memory. IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x() - offset, 0, lastline.width() + offset, 0); IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x() - offset, 0, nextline.width() + offset, 0); const int fallbackMaxOutlineX = std::numeric_limits<int>::max(); const int fallbackMinOutlineX = std::numeric_limits<int>::min(); // left edge ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), pixelSnappedBox.x(), pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), BSLeft, outlineColor, outlineStyle, (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), antialias); // right edge ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.maxX(), pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0), BSRight, outlineColor, outlineStyle, (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth), (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth), antialias); // upper edge if (thisline.x() < lastline.x()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - outlineWidth, std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? fallbackMaxOutlineX : pixelSnappedLastLine.x())), pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, outlineWidth, (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, antialias); } if (lastline.maxX() < thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, std::max(lastline.isEmpty() ? fallbackMinOutlineX : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.y() - outlineWidth, pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth, outlineWidth, antialias); } if (thisline.x() == thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.y() - outlineWidth, pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.y(), BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth, antialias); } // lower edge if (thisline.x() < nextline.x()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.maxY(), std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : fallbackMaxOutlineX), pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, outlineWidth, (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, antialias); } if (nextline.maxX() < thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : fallbackMinOutlineX, pixelSnappedBox.x() - outlineWidth), pixelSnappedBox.maxY(), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth, outlineWidth, antialias); } if (thisline.x() == thisline.maxX()) { ObjectPainter::drawLineForBoxSide(graphicsContext, pixelSnappedBox.x() - outlineWidth, pixelSnappedBox.maxY(), pixelSnappedBox.maxX() + outlineWidth, pixelSnappedBox.maxY() + outlineWidth, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth, antialias); } }
bool RenderView::shouldRepaint(const LayoutRect& rect) const { return !printing() && !rect.isEmpty(); }
bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusDirection direction, KeyboardEvent* event) { if (!container || !container->document()) return false; LayoutRect newStartingRect = startingRect; if (startingRect.isEmpty()) newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container)); // Find the closest node within current container in the direction of the navigation. FocusCandidate focusCandidate; findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate); if (focusCandidate.isNull()) { // Nothing to focus, scroll if possible. // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the // spatial navigation algorithm will skip this container. return scrollInDirection(container, direction); } if (HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate)) { // If we have an iframe without the src attribute, it will not have a contentFrame(). // We ASSERT here to make sure that // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate. ASSERT(frameElement->contentFrame()); if (focusCandidate.isOffscreenAfterScrolling) { scrollInDirection(focusCandidate.visibleNode->document(), direction); return true; } // Navigate into a new frame. LayoutRect rect; Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); if (focusedNode && !hasOffscreenRect(focusedNode)) rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets(); if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) { // The new frame had nothing interesting, need to find another candidate. return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), direction, event); } return true; } if (canScrollInDirection(focusCandidate.visibleNode, direction)) { if (focusCandidate.isOffscreenAfterScrolling) { scrollInDirection(focusCandidate.visibleNode, direction); return true; } // Navigate into a new scrollable container. LayoutRect startingRect; Node* focusedNode = focusedOrMainFrame()->document()->focusedNode(); if (focusedNode && !hasOffscreenRect(focusedNode)) startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true); return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event); } if (focusCandidate.isOffscreenAfterScrolling) { Node* container = focusCandidate.enclosingScrollableBox; scrollInDirection(container, direction); return true; } // We found a new focus node, navigate to it. Element* element = toElement(focusCandidate.focusableNode); ASSERT(element); element->focus(false); return true; }
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.context, LayoutRect(adjustedPaintOffset, size())); if (!m_frameView || paintInfo.phase != PaintPhaseForeground) return; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(paintOffset, style()->highlight(), true); #endif 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(); RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderRect, paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true); clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect); } if (m_widget) { // 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. IntPoint widgetLocation = m_widget->frameRect().location(); IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()), roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); IntRect paintRect = paintInfo.rect; IntSize widgetPaintOffset = paintLocation - widgetLocation; // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer, // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing. if (!widgetPaintOffset.isZero()) { paintInfo.context->translate(widgetPaintOffset); paintRect.move(-widgetPaintOffset); } m_widget->paint(paintInfo.context, paintRect); if (!widgetPaintOffset.isZero()) paintInfo.context->translate(-widgetPaintOffset); if (m_widget->isFrameView()) { FrameView* frameView = static_cast<FrameView*>(m_widget.get()); bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContentIncludingDescendants(); if (paintInfo.overlapTestRequests && runOverlapTests) { ASSERT(!paintInfo.overlapTestRequests->contains(this)); paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); } } } 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(pixelSnappedIntRect(selectionRect()), selectionBackgroundColor(), style()->colorSpace()); } }
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()); } }
bool RenderView::shouldRepaint(const LayoutRect& rect) const { if (document().printing()) return false; return m_frameView && !rect.isEmpty(); }