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 && !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); 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)); }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. if (paintInfo.context->paintingDisabled()) return; Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); } childPaintInfo.context->restore(); }
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 RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Page* page = frame().page(); if (isPluginUnavailable()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); RenderReplaced::paint(paintInfo, paintOffset); return; } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); RenderWidget::paint(paintInfo, paintOffset); }
void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); if (showsUnavailablePluginIndicator()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); RenderReplaced::paint(paintInfo, paintOffset); return; } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); RenderPart::paint(paintInfo, paintOffset); }
void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Page* page = frame().page(); // The relevant repainted object heuristic is not tuned for plugin documents. bool countsTowardsRelevantObjects = page && !document().isPluginDocument() && paintInfo.phase == PaintPhaseForeground; if (isPluginUnavailable()) { if (countsTowardsRelevantObjects) page->addRelevantUnpaintedObject(this, visualOverflowRect()); RenderReplaced::paint(paintInfo, paintOffset); return; } if (countsTowardsRelevantObjects) page->addRelevantRepaintedObject(this, visualOverflowRect()); RenderWidget::paint(paintInfo, paintOffset); }
void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = contentWidth(); LayoutUnit cHeight = contentHeight(); LayoutUnit leftBorder = borderLeft(); LayoutUnit topBorder = borderTop(); LayoutUnit leftPad = paddingLeft(); LayoutUnit topPad = paddingTop(); GraphicsContext* context = paintInfo.context; Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); if (cWidth > 2 && cHeight > 2) { // Draw an outline rect where the image should be. context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray, style()->colorSpace()); context->setFillColor(Color::transparent, style()->colorSpace()); context->drawRect(pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight))); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2; LayoutUnit usableHeight = cHeight - 2; RefPtr<Image> image = m_imageResource->image(); if (m_imageResource->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { float deviceScaleFactor = WebCore::deviceScaleFactor(frame()); // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. pair<Image*, float> brokenImageAndImageScaleFactor = m_imageResource->cachedImage()->brokenImage(deviceScaleFactor); image = brokenImageAndImageScaleFactor.first; IntSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + 1, topBorder + topPad + centerY + 1); context->drawImage(image.get(), style()->colorSpace(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, shouldRespectImageOrientation()); errorPictureDrawn = true; } if (!m_altText.isEmpty()) { String text = document()->displayStringModifiedByEncoding(m_altText); context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace()); const Font& font = style()->font(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint altTextOffset = paintOffset; altTextOffset.move(leftBorder + leftPad, topBorder + topPad + ascent); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = RenderBlock::constructTextRun(this, font, text, style()); LayoutUnit textWidth = font.width(textRun); if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context->drawText(font, textRun, altTextOffset); } else if (usableWidth >= textWidth && cHeight >= fontMetrics.height()) context->drawText(font, textRun, altTextOffset); } } } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) { RefPtr<Image> img = m_imageResource->image(cWidth, cHeight); if (!img || img->isNull()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(toPoint(paintOffset - location()), style()->highlight(), true); #endif LayoutSize contentSize(cWidth, cHeight); LayoutPoint contentLocation = paintOffset; contentLocation.move(leftBorder + leftPad, topBorder + topPad); paintIntoRect(context, LayoutRect(contentLocation, contentSize)); if (cachedImage() && page && paintInfo.phase == PaintPhaseForeground) { // For now, count images as unpainted if they are still progressively loading. We may want // to refine this in the future to account for the portion of the image that has painted. if (cachedImage()->isLoading()) page->addRelevantUnpaintedObject(this, LayoutRect(contentLocation, contentSize)); else page->addRelevantRepaintedObject(this, LayoutRect(contentLocation, contentSize)); } } }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. if (paintInfo.context->paintingDisabled()) return; // SVG outlines are painted during PaintPhaseForeground. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) if (svgSVGElement().hasEmptyViewBox()) return; Page* page = frame().page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip if (shouldApplyViewportClip()) childPaintInfo.context->clip(snappedIntRect(overflowClipRect(paintOffset, currentRenderNamedFlowFragment()))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(*this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) { childPaintInfo.updateSubtreePaintRootForChildren(this); for (auto& child : childrenOfType<RenderElement>(*this)) child.paint(childPaintInfo, location()); } } childPaintInfo.context->restore(); }
void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = contentWidth(); LayoutUnit cHeight = contentHeight(); LayoutUnit leftBorder = borderLeft(); LayoutUnit topBorder = borderTop(); LayoutUnit leftPad = paddingLeft(); LayoutUnit topPad = paddingTop(); GraphicsContext& context = paintInfo.context(); float deviceScaleFactor = document().deviceScaleFactor(); Page* page = frame().page(); if (!imageResource().hasImage() || imageResource().errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); if (cWidth > 2 && cHeight > 2) { LayoutUnit borderWidth = LayoutUnit(1 / deviceScaleFactor); // Draw an outline rect where the image should be. context.setStrokeStyle(SolidStroke); context.setStrokeColor(Color::lightGray, style().colorSpace()); context.setFillColor(Color::transparent, style().colorSpace()); context.drawRect(snapRectToDevicePixels(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight), deviceScaleFactor), borderWidth); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2 * borderWidth; LayoutUnit usableHeight = cHeight - 2 * borderWidth; RefPtr<Image> image = imageResource().image(); if (imageResource().errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. std::pair<Image*, float> brokenImageAndImageScaleFactor = imageResource().cachedImage()->brokenImage(document().deviceScaleFactor()); image = brokenImageAndImageScaleFactor.first; FloatSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth); ImageOrientationDescription orientationDescription(shouldRespectImageOrientation()); #if ENABLE(CSS_IMAGE_ORIENTATION) orientationDescription.setImageOrientationEnum(style().imageOrientation()); #endif context.drawImage(*image, style().colorSpace(), snapRectToDevicePixels(LayoutRect(paintOffset + imageOffset, imageSize), deviceScaleFactor), orientationDescription); errorPictureDrawn = true; } if (!m_altText.isEmpty()) { String text = document().displayStringModifiedByEncoding(m_altText); context.setFillColor(style().visitedDependentColor(CSSPropertyColor), style().colorSpace()); const FontCascade& font = style().fontCascade(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint altTextOffset = paintOffset; altTextOffset.move(leftBorder + leftPad + (paddingWidth / 2) - borderWidth, topBorder + topPad + ascent + (paddingHeight / 2) - borderWidth); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = RenderBlock::constructTextRun(this, font, text, style()); LayoutUnit textWidth = font.width(textRun); if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context.drawText(font, textRun, altTextOffset); } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) context.drawText(font, textRun, altTextOffset); } } } else if (imageResource().hasImage() && cWidth > 0 && cHeight > 0) { RefPtr<Image> img = imageResource().image(cWidth, cHeight); if (!img || img->isNull()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } LayoutRect contentBoxRect = this->contentBoxRect(); contentBoxRect.moveBy(paintOffset); LayoutRect replacedContentRect = this->replacedContentRect(intrinsicSize()); replacedContentRect.moveBy(paintOffset); bool clip = !contentBoxRect.contains(replacedContentRect); GraphicsContextStateSaver stateSaver(context, clip); if (clip) context.clip(contentBoxRect); paintIntoRect(context, snapRectToDevicePixels(replacedContentRect, deviceScaleFactor)); if (cachedImage() && page && paintInfo.phase == PaintPhaseForeground) { // For now, count images as unpainted if they are still progressively loading. We may want // to refine this in the future to account for the portion of the image that has painted. LayoutRect visibleRect = intersection(replacedContentRect, contentBoxRect); if (cachedImage()->isLoading()) page->addRelevantUnpaintedObject(this, visibleRect); else page->addRelevantRepaintedObject(this, visibleRect); } } }