NS_IMETHODIMP nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return NS_OK; // If mozpasspointerevents is set, then we should allow subdocument content // to handle events even if we're pointer-events:none. if (aBuilder->IsForEventDelivery() && !PassPointerEventsToChildren()) return NS_OK; nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); NS_ENSURE_SUCCESS(rv, rv); if (!mInnerView) return NS_OK; nsFrameLoader* frameLoader = FrameLoader(); if (frameLoader) { RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame(); if (rfp) { return rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); } } nsIView* subdocView = mInnerView->GetFirstChild(); if (!subdocView) return NS_OK; nsCOMPtr<nsIPresShell> presShell = nullptr; nsIFrame* subdocRootFrame = subdocView->GetFrame(); if (subdocRootFrame) { presShell = subdocRootFrame->PresContext()->PresShell(); } // If painting is suppressed in the presshell, we try to look for a better // presshell to use. if (!presShell || (presShell->IsPaintingSuppressed() && !aBuilder->IsIgnoringPaintSuppression())) { // During page transition mInnerView will sometimes have two children, the // first being the new page that may not have any frame, and the second // being the old page that will probably have a frame. nsIView* nextView = subdocView->GetNextSibling(); nsIFrame* frame = nullptr; if (nextView) { frame = nextView->GetFrame(); } if (frame) { nsIPresShell* ps = frame->PresContext()->PresShell(); if (!presShell || (ps && !ps->IsPaintingSuppressed())) { subdocView = nextView; subdocRootFrame = frame; presShell = ps; } } if (!presShell) { // If we don't have a frame we use this roundabout way to get the pres shell. if (!mFrameLoader) return NS_OK; nsCOMPtr<nsIDocShell> docShell; mFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) return NS_OK; docShell->GetPresShell(getter_AddRefs(presShell)); if (!presShell) return NS_OK; } } nsPresContext* presContext = presShell->GetPresContext(); nsDisplayList childItems; int32_t parentAPD = PresContext()->AppUnitsPerDevPixel(); int32_t subdocAPD = presContext->AppUnitsPerDevPixel(); nsRect dirty; if (subdocRootFrame) { nsIDocument* doc = subdocRootFrame->PresContext()->Document(); nsIContent* root = doc ? doc->GetRootElement() : nullptr; nsRect displayPort; if (root && nsLayoutUtils::GetDisplayPort(root, &displayPort)) { dirty = displayPort; } else { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } aBuilder->EnterPresShell(subdocRootFrame, dirty); } nsRect subdocBoundsInParentUnits = mInnerView->GetBounds() + aBuilder->ToReferenceFrame(this); if (subdocRootFrame) { rv = subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds; if (subdocRootFrame) { bounds = subdocBoundsInParentUnits.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } else { bounds = subdocBoundsInParentUnits; } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { rv = presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. uint32_t flags = nsIPresShell::FORCE_DRAW; rv = presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds, NS_RGBA(0,0,0,0), flags); } } bool addedLayer = false; if (subdocRootFrame && parentAPD != subdocAPD) { NS_WARN_IF_FALSE(!addedLayer, "Two container layers have been added. " "Performance may suffer."); addedLayer = true; nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); childItems.AppendToTop(zoomItem); } nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable(); if (!addedLayer && (presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive()))) { // We always want top level content documents to be in their own layer. nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); childItems.AppendToTop(layerItem); } if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, dirty); } if (ShouldClipSubdocument()) { nsDisplayClip* item = new (aBuilder) nsDisplayClip(aBuilder, this, &childItems, subdocBoundsInParentUnits); // Clip children to the child root frame's rectangle childItems.AppendToTop(item); } if (mIsInline) { WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists); } else { aLists.Content()->AppendToTop(&childItems); } // delete childItems in case of OOM childItems.DeleteAll(); return rv; }
void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return; nsFrameLoader* frameLoader = FrameLoader(); RenderFrameParent* rfp = nullptr; if (frameLoader) { rfp = frameLoader->GetCurrentRemoteFrame(); } // If we are pointer-events:none then we don't need to HitTest background bool pointerEventsNone = StyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE; if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) { nsDisplayListCollection decorations; DisplayBorderBackgroundOutline(aBuilder, decorations); if (rfp) { // Wrap background colors of <iframe>s with remote subdocuments in their // own layer so we generate a ColorLayer. This is helpful for optimizing // compositing; we can skip compositing the ColorLayer when the // remote content is opaque. WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground()); } decorations.MoveTo(aLists); } bool passPointerEventsToChildren = false; if (aBuilder->IsForEventDelivery()) { passPointerEventsToChildren = PassPointerEventsToChildren(); // If mozpasspointerevents is set, then we should allow subdocument content // to handle events even if we're pointer-events:none. if (pointerEventsNone && !passPointerEventsToChildren) { return; } } // If we're passing pointer events to children then we have to descend into // subdocuments no matter what, to determine which parts are transparent for // elementFromPoint. if (!mInnerView || (!aBuilder->GetDescendIntoSubdocuments() && !passPointerEventsToChildren)) { return; } if (rfp) { rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); return; } nsView* subdocView = mInnerView->GetFirstChild(); if (!subdocView) return; nsCOMPtr<nsIPresShell> presShell = nullptr; nsIFrame* subdocRootFrame = subdocView->GetFrame(); if (subdocRootFrame) { presShell = subdocRootFrame->PresContext()->PresShell(); } // If painting is suppressed in the presshell, we try to look for a better // presshell to use. if (!presShell || (presShell->IsPaintingSuppressed() && !aBuilder->IsIgnoringPaintSuppression())) { // During page transition mInnerView will sometimes have two children, the // first being the new page that may not have any frame, and the second // being the old page that will probably have a frame. nsView* nextView = subdocView->GetNextSibling(); nsIFrame* frame = nullptr; if (nextView) { frame = nextView->GetFrame(); } if (frame) { nsIPresShell* ps = frame->PresContext()->PresShell(); if (!presShell || (ps && !ps->IsPaintingSuppressed())) { subdocView = nextView; subdocRootFrame = frame; presShell = ps; } } if (!presShell) { // If we don't have a frame we use this roundabout way to get the pres shell. if (!mFrameLoader) return; nsCOMPtr<nsIDocShell> docShell; mFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) return; presShell = docShell->GetPresShell(); if (!presShell) return; } } nsPresContext* presContext = presShell->GetPresContext(); int32_t parentAPD = PresContext()->AppUnitsPerDevPixel(); int32_t subdocAPD = presContext->AppUnitsPerDevPixel(); nsRect dirty; bool haveDisplayPort = false; bool ignoreViewportScrolling = false; nsIFrame* savedIgnoreScrollFrame = nullptr; if (subdocRootFrame) { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) { // for root content documents we want the base to be the composition bounds nsRect displayportBase = presContext->IsRootContentDocument() ? nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) : dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize())); nsRect displayPort; if (nsLayoutUtils::GetOrMaybeCreateDisplayPort( *aBuilder, rootScrollFrame, displayportBase, &displayPort)) { haveDisplayPort = true; dirty = displayPort; } ignoreViewportScrolling = presShell->IgnoringViewportScrolling(); if (ignoreViewportScrolling) { savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame(); aBuilder->SetIgnoreScrollFrame(rootScrollFrame); } } aBuilder->EnterPresShell(subdocRootFrame, dirty); } DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (ShouldClipSubdocument()) { clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this); } nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable(); bool constructResolutionItem = subdocRootFrame && (presShell->GetXResolution() != 1.0 || presShell->GetYResolution() != 1.0); bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD; bool needsOwnLayer = constructResolutionItem || constructZoomItem || haveDisplayPort || presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive()); // Don't let in fixed pos propagate down to child documents. This makes // it a little less effective but doesn't regress an important case of a // child document being in a fixed pos element where we would do no occlusion // at all if we let it propagate down. nsDisplayListBuilder::AutoInFixedPosSetter buildingInFixedPos(aBuilder, false); nsDisplayList childItems; { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); if (needsOwnLayer) { // Clear current clip. There's no point in propagating it down, since // the layer we will construct will be clipped by the current clip. // In fact for nsDisplayZoom propagating it down would be incorrect since // nsDisplayZoom changes the meaning of appunits. nestedClipState.Clear(); } if (subdocRootFrame) { nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter( aBuilder, ignoreViewportScrolling && subdocRootFrame->GetContent() ? nsLayoutUtils::FindOrCreateIDFor(subdocRootFrame->GetContent()) : aBuilder->GetCurrentScrollParentId()); aBuilder->SetAncestorHasTouchEventHandler(false); subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds = GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); if (subdocRootFrame) { bounds = bounds.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. uint32_t flags = nsIPresShell::FORCE_DRAW; presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds, NS_RGBA(0,0,0,0), flags); } } } // Generate a resolution and/or zoom item if needed. If one or both of those is // created, we don't need to create a separate nsDisplaySubDocument. uint32_t flags = nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS; // If ignoreViewportScrolling is true then the top most layer we create here // is going to become the scrollable layer for the root scroll frame, so we // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer // becomes the topmost. We do this below. if (constructZoomItem) { uint32_t zoomFlags = flags; if (ignoreViewportScrolling && !constructResolutionItem) { zoomFlags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER; } nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD, zoomFlags); childItems.AppendToTop(zoomItem); needsOwnLayer = false; } // Wrap the zoom item in the resolution item if we have both because we want the // resolution scale applied on top of the app units per dev pixel conversion. if (ignoreViewportScrolling) { flags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER; } if (constructResolutionItem) { nsDisplayResolution* resolutionItem = new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems, flags); childItems.AppendToTop(resolutionItem); needsOwnLayer = false; } if (needsOwnLayer) { // We always want top level content documents to be in their own layer. nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems, flags); childItems.AppendToTop(layerItem); } if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, dirty); if (ignoreViewportScrolling) { aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame); } } if (aBuilder->IsForImageVisibility()) { // We don't add the childItems to the return list as we're dealing with them here. presShell->RebuildImageVisibility(childItems); childItems.DeleteAll(); } else { aLists.Content()->AppendToTop(&childItems); } }
void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return; nsFrameLoader* frameLoader = FrameLoader(); RenderFrameParent* rfp = nullptr; if (frameLoader) { rfp = frameLoader->GetCurrentRenderFrame(); } // If we are pointer-events:none then we don't need to HitTest background bool pointerEventsNone = StyleUserInterface()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE; if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) { nsDisplayListCollection decorations; DisplayBorderBackgroundOutline(aBuilder, decorations); if (rfp) { // Wrap background colors of <iframe>s with remote subdocuments in their // own layer so we generate a ColorLayer. This is helpful for optimizing // compositing; we can skip compositing the ColorLayer when the // remote content is opaque. WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground()); } decorations.MoveTo(aLists); } if (aBuilder->IsForEventDelivery() && pointerEventsNone) { return; } // If we're passing pointer events to children then we have to descend into // subdocuments no matter what, to determine which parts are transparent for // hit-testing or event regions. bool needToDescend = aBuilder->GetDescendIntoSubdocuments(); if (!mInnerView || !needToDescend) { return; } if (rfp) { rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); return; } nsCOMPtr<nsIPresShell> presShell = GetSubdocumentPresShellForPainting( aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0); if (!presShell) { return; } nsIFrame* subdocRootFrame = presShell->GetRootFrame(); nsPresContext* presContext = presShell->GetPresContext(); int32_t parentAPD = PresContext()->AppUnitsPerDevPixel(); int32_t subdocAPD = presContext->AppUnitsPerDevPixel(); nsRect dirty; bool haveDisplayPort = false; bool ignoreViewportScrolling = false; nsIFrame* savedIgnoreScrollFrame = nullptr; if (subdocRootFrame) { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) { nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable(); MOZ_ASSERT(rootScrollableFrame); // Use a copy, so the dirty rect doesn't get modified to the display port. nsRect copy = dirty; haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder, ©, /* aAllowCreateDisplayPort = */ true); if (!gfxPrefs::LayoutUseContainersForRootFrames()) { haveDisplayPort = false; } ignoreViewportScrolling = presShell->IgnoringViewportScrolling(); if (ignoreViewportScrolling) { savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame(); aBuilder->SetIgnoreScrollFrame(rootScrollFrame); } } aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone); } else { dirty = aDirtyRect; } DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (ShouldClipSubdocument()) { clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this); } nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable(); bool constructResolutionItem = subdocRootFrame && (presShell->GetResolution() != 1.0); bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD; bool needsOwnLayer = false; if (constructResolutionItem || constructZoomItem || haveDisplayPort || presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive(aBuilder))) { needsOwnLayer = true; } if (!needsOwnLayer && aBuilder->IsBuildingLayerEventRegions() && nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell)) { needsOwnLayer = true; } nsDisplayList childItems; { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); if (needsOwnLayer) { // Clear current clip. There's no point in propagating it down, since // the layer we will construct will be clipped by the current clip. // In fact for nsDisplayZoom propagating it down would be incorrect since // nsDisplayZoom changes the meaning of appunits. nestedClipState.EnterStackingContextContents(true); } if (subdocRootFrame) { nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter( aBuilder, ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent() ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent()) : aBuilder->GetCurrentScrollParentId()); aBuilder->SetAncestorHasApzAwareEventHandler(false); subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds = GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); if (subdocRootFrame) { bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect // is used to compute the visible rect if AddCanvasBackgroundColorItem // creates a display item. nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this; nsDisplayListBuilder::AutoBuildingDisplayList building(aBuilder, frame, dirty, true); // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. uint32_t flags = nsIPresShell::FORCE_DRAW; presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, frame, bounds, NS_RGBA(0,0,0,0), flags); } } } if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, &childItems); if (ignoreViewportScrolling) { aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame); } } // Generate a resolution and/or zoom item if needed. If one or both of those is // created, we don't need to create a separate nsDisplaySubDocument. uint32_t flags = nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS; // If ignoreViewportScrolling is true then the top most layer we create here // is going to become the scrollable layer for the root scroll frame, so we // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer // becomes the topmost. We do this below. if (constructZoomItem) { uint32_t zoomFlags = flags; if (ignoreViewportScrolling && !constructResolutionItem) { zoomFlags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER; } nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD, zoomFlags); childItems.AppendToTop(zoomItem); needsOwnLayer = false; } // Wrap the zoom item in the resolution item if we have both because we want the // resolution scale applied on top of the app units per dev pixel conversion. if (ignoreViewportScrolling) { flags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER; } if (constructResolutionItem) { nsDisplayResolution* resolutionItem = new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems, flags); childItems.AppendToTop(resolutionItem); needsOwnLayer = false; } if (needsOwnLayer) { // We always want top level content documents to be in their own layer. nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems, flags); childItems.AppendToTop(layerItem); } if (aBuilder->IsForFrameVisibility()) { // We don't add the childItems to the return list as we're dealing with them here. presShell->RebuildApproximateFrameVisibilityDisplayList(childItems); childItems.DeleteAll(); } else { aLists.Content()->AppendToTop(&childItems); } }
void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return; // If mozpasspointerevents is set, then we should allow subdocument content // to handle events even if we're pointer-events:none. if (aBuilder->IsForEventDelivery() && !PassPointerEventsToChildren()) return; DisplayBorderBackgroundOutline(aBuilder, aLists); if (!mInnerView) return; nsFrameLoader* frameLoader = FrameLoader(); if (frameLoader) { RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame(); if (rfp) { rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); return; } } nsView* subdocView = mInnerView->GetFirstChild(); if (!subdocView) return; nsCOMPtr<nsIPresShell> presShell = nullptr; nsIFrame* subdocRootFrame = subdocView->GetFrame(); if (subdocRootFrame) { presShell = subdocRootFrame->PresContext()->PresShell(); } // If painting is suppressed in the presshell, we try to look for a better // presshell to use. if (!presShell || (presShell->IsPaintingSuppressed() && !aBuilder->IsIgnoringPaintSuppression())) { // During page transition mInnerView will sometimes have two children, the // first being the new page that may not have any frame, and the second // being the old page that will probably have a frame. nsView* nextView = subdocView->GetNextSibling(); nsIFrame* frame = nullptr; if (nextView) { frame = nextView->GetFrame(); } if (frame) { nsIPresShell* ps = frame->PresContext()->PresShell(); if (!presShell || (ps && !ps->IsPaintingSuppressed())) { subdocView = nextView; subdocRootFrame = frame; presShell = ps; } } if (!presShell) { // If we don't have a frame we use this roundabout way to get the pres shell. if (!mFrameLoader) return; nsCOMPtr<nsIDocShell> docShell; mFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) return; presShell = docShell->GetPresShell(); if (!presShell) return; } } nsPresContext* presContext = presShell->GetPresContext(); int32_t parentAPD = PresContext()->AppUnitsPerDevPixel(); int32_t subdocAPD = presContext->AppUnitsPerDevPixel(); nsRect dirty; if (subdocRootFrame) { nsIDocument* doc = subdocRootFrame->PresContext()->Document(); nsIContent* root = doc ? doc->GetRootElement() : nullptr; nsRect displayPort; if (root && nsLayoutUtils::GetDisplayPort(root, &displayPort)) { dirty = displayPort; } else { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } aBuilder->EnterPresShell(subdocRootFrame, dirty); } DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (ShouldClipSubdocument()) { clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this); } nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable(); bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD; bool needsOwnLayer = constructZoomItem || presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive()); nsDisplayList childItems; { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); if (needsOwnLayer) { // Clear current clip. There's no point in propagating it down, since // the layer we will construct will be clipped by the current clip. // In fact for nsDisplayZoom propagating it down would be incorrect since // nsDisplayZoom changes the meaning of appunits. nestedClipState.Clear(); } if (subdocRootFrame) { subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds; nsRect subdocBoundsInParentUnits = GetContentRectRelativeToSelf(); if (subdocRootFrame) { bounds = subdocBoundsInParentUnits.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } else { bounds = subdocBoundsInParentUnits; } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. uint32_t flags = nsIPresShell::FORCE_DRAW; presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds, NS_RGBA(0,0,0,0), flags); } } } if (constructZoomItem) { nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); childItems.AppendToTop(zoomItem); } else if (needsOwnLayer) { // We always want top level content documents to be in their own layer. nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); childItems.AppendToTop(layerItem); } if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, dirty); } if (aBuilder->IsForImageVisibility()) { // We don't add the childItems to the return list as we're dealing with them here. presShell->RebuildImageVisibility(childItems); childItems.DeleteAll(); } else { aLists.Content()->AppendToTop(&childItems); } }
NS_IMETHODIMP nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return NS_OK; if (aBuilder->IsForEventDelivery() && GetStyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE) return NS_OK; nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); NS_ENSURE_SUCCESS(rv, rv); if (!mInnerView) return NS_OK; nsFrameLoader* frameLoader = FrameLoader(); if (frameLoader) { RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame(); if (rfp) { return rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); } } nsIView* subdocView = mInnerView->GetFirstChild(); if (!subdocView) return NS_OK; nsCOMPtr<nsIPresShell> presShell = nsnull; nsIFrame* subdocRootFrame = static_cast<nsIFrame*>(subdocView->GetClientData()); if (subdocRootFrame) { presShell = subdocRootFrame->PresContext()->PresShell(); } // If painting is suppressed in the presshell, we try to look for a better // presshell to use. if (!presShell || (presShell->IsPaintingSuppressed() && !aBuilder->IsIgnoringPaintSuppression())) { // During page transition mInnerView will sometimes have two children, the // first being the new page that may not have any frame, and the second // being the old page that will probably have a frame. nsIView* nextView = subdocView->GetNextSibling(); nsIFrame* frame = nsnull; if (nextView) { frame = static_cast<nsIFrame*>(nextView->GetClientData()); } if (frame) { nsIPresShell* ps = frame->PresContext()->PresShell(); if (!presShell || (ps && !ps->IsPaintingSuppressed())) { subdocView = nextView; subdocRootFrame = frame; presShell = ps; } } if (!presShell) { // If we don't have a frame we use this roundabout way to get the pres shell. if (!mFrameLoader) return NS_OK; nsCOMPtr<nsIDocShell> docShell; mFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) return NS_OK; docShell->GetPresShell(getter_AddRefs(presShell)); if (!presShell) return NS_OK; } } nsPresContext* presContext = presShell->GetPresContext(); nsDisplayList childItems; PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel(); PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel(); nsRect dirty; if (subdocRootFrame) { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); aBuilder->EnterPresShell(subdocRootFrame, dirty); } // The subdocView's bounds are in appunits of the subdocument, so adjust // them. nsRect subdocBoundsInParentUnits = subdocView->GetBounds().ConvertAppUnitsRoundOut(subdocAPD, parentAPD); // Get the bounds of subdocView relative to the reference frame. subdocBoundsInParentUnits = subdocBoundsInParentUnits + mInnerView->GetPosition() + GetOffsetToCrossDoc(aBuilder->ReferenceFrame()); if (subdocRootFrame && NS_SUCCEEDED(rv)) { rv = subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds; if (subdocRootFrame) { nsPoint offset = mInnerView->GetPosition() + GetOffsetToCrossDoc(aBuilder->ReferenceFrame()); offset = offset.ConvertAppUnits(parentAPD, subdocAPD); bounds = subdocView->GetBounds() + offset; } else { bounds = subdocBoundsInParentUnits; } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { rv = presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. PRUint32 flags = nsIPresShell::FORCE_DRAW; rv = presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds, NS_RGBA(0,0,0,0), flags); } } if (NS_SUCCEEDED(rv)) { bool addedLayer = false; if (subdocRootFrame && parentAPD != subdocAPD) { NS_WARN_IF_FALSE(!addedLayer, "Two container layers have been added. " "Performance may suffer."); addedLayer = true; nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD); childItems.AppendToTop(zoomItem); } if (!addedLayer && presContext->IsRootContentDocument()) { // We always want top level content documents to be in their own layer. nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems); childItems.AppendToTop(layerItem); } nsDisplayList list; // Clip children to the child root frame's rectangle rv = list.AppendNewToTop( new (aBuilder) nsDisplayClip(aBuilder, this, &childItems, subdocBoundsInParentUnits)); if (mIsInline) { WrapReplacedContentForBorderRadius(aBuilder, &list, aLists); } else { aLists.Content()->AppendToTop(&list); } } // delete childItems in case of OOM childItems.DeleteAll(); if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, dirty); } return rv; }
NS_IMETHODIMP nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return NS_OK; if (aBuilder->IsForEventDelivery() && GetStyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE) return NS_OK; nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists); NS_ENSURE_SUCCESS(rv, rv); if (!mInnerView) return NS_OK; #ifdef MOZ_IPC nsFrameLoader* frameLoader = FrameLoader(); if (frameLoader) { RenderFrameParent* rfp = frameLoader->GetCurrentRemoteFrame(); if (rfp) { return rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists); } } #endif nsIView* subdocView = mInnerView->GetFirstChild(); if (!subdocView) return NS_OK; nsCOMPtr<nsIPresShell> presShell = nsnull; nsIFrame* subdocRootFrame = static_cast<nsIFrame*>(subdocView->GetClientData()); if (subdocRootFrame) { presShell = subdocRootFrame->PresContext()->PresShell(); } // If painting is suppressed in the presshell, we try to look for a better // presshell to use. if (!presShell || (presShell->IsPaintingSuppressed() && !aBuilder->IsIgnoringPaintSuppression())) { // During page transition mInnerView will sometimes have two children, the // first being the new page that may not have any frame, and the second // being the old page that will probably have a frame. nsIView* nextView = subdocView->GetNextSibling(); nsIFrame* frame = nsnull; if (nextView) { frame = static_cast<nsIFrame*>(nextView->GetClientData()); } if (frame) { nsIPresShell* ps = frame->PresContext()->PresShell(); if (!presShell || (ps && !ps->IsPaintingSuppressed())) { subdocView = nextView; subdocRootFrame = frame; presShell = ps; } } if (!presShell) { // If we don't have a frame we use this roundabout way to get the pres shell. if (!mFrameLoader) return NS_OK; nsCOMPtr<nsIDocShell> docShell; mFrameLoader->GetDocShell(getter_AddRefs(docShell)); if (!docShell) return NS_OK; docShell->GetPresShell(getter_AddRefs(presShell)); if (!presShell) return NS_OK; } } nsPresContext* presContext = presShell->GetPresContext(); nsDisplayList childItems; PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel(); PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel(); nsIFrame* subdocRootScrollFrame = presShell->GetRootScrollFrame(); nsRect dirty; if (subdocRootFrame) { if (presShell->UsingDisplayPort() && subdocRootScrollFrame) { dirty = presShell->GetDisplayPort(); // The visual overflow rect of our viewport frame unfortunately may not // intersect with the displayport of that frame. For example, the scroll // offset of the frame may be (0, 0) so that the visual overflow rect // is (0, 0, 800px, 500px) while the display port may have its top-left // corner below y=500px. // // We have to force the frame to have a little faith and build a display // list anyway. (see nsIFrame::BuildDisplayListForChild for the short- // circuit code we are evading here). // subdocRootScrollFrame->AddStateBits( NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO); } else { // get the dirty rect relative to the root frame of the subdoc dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); // and convert into the appunits of the subdoc dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); } aBuilder->EnterPresShell(subdocRootFrame, dirty); } // The subdocView's bounds are in appunits of the subdocument, so adjust // them. nsRect subdocBoundsInParentUnits = subdocView->GetBounds().ConvertAppUnitsRoundOut(subdocAPD, parentAPD); // Get the bounds of subdocView relative to the reference frame. subdocBoundsInParentUnits = subdocBoundsInParentUnits + mInnerView->GetPosition() + GetOffsetToCrossDoc(aBuilder->ReferenceFrame()); if (subdocRootFrame && NS_SUCCEEDED(rv)) { rv = subdocRootFrame-> BuildDisplayListForStackingContext(aBuilder, dirty, &childItems); } if (!aBuilder->IsForEventDelivery()) { // If we are going to use a displayzoom below then any items we put under // it need to have underlying frames from the subdocument. So we need to // calculate the bounds based on which frame will be the underlying frame // for the canvas background color item. nsRect bounds; if (subdocRootFrame) { nsPoint offset = mInnerView->GetPosition() + GetOffsetToCrossDoc(aBuilder->ReferenceFrame()); offset = offset.ConvertAppUnits(parentAPD, subdocAPD); bounds = subdocView->GetBounds() + offset; } else { bounds = subdocBoundsInParentUnits; } // If we are in print preview/page layout we want to paint the grey // background behind the page, not the canvas color. The canvas color gets // painted on the page itself. if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) { rv = presShell->AddPrintPreviewBackgroundItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds); } else { // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. PRUint32 flags = nsIPresShell_MOZILLA_2_0_BRANCH::FORCE_DRAW; if (presContext->IsRootContentDocument()) { flags |= nsIPresShell_MOZILLA_2_0_BRANCH::ROOT_CONTENT_DOC_BG; } rv = presShell->AddCanvasBackgroundColorItem( *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this, bounds, NS_RGBA(0,0,0,0), flags); } } if (NS_SUCCEEDED(rv)) { bool addedLayer = false; #ifdef MOZ_IPC // Make a scrollable layer in the child process so it can be manipulated // with transforms in the parent process. if (XRE_GetProcessType() == GeckoProcessType_Content) { nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable(); if (scrollFrame) { NS_ASSERTION(subdocRootFrame, "Root scroll frame should be non-null"); nsRect scrollRange = scrollFrame->GetScrollRange(); // Since making new layers is expensive, only use nsDisplayScrollLayer // if the area is scrollable. if (scrollRange.width != 0 || scrollRange.height != 0) { addedLayer = true; nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer( aBuilder, &childItems, subdocRootScrollFrame, subdocRootFrame ); childItems.AppendToTop(layerItem); } } } #endif if (subdocRootFrame && parentAPD != subdocAPD) { NS_WARN_IF_FALSE(!addedLayer, "Two container layers have been added. " "Performance may suffer."); addedLayer = true; nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, subdocAPD, parentAPD); childItems.AppendToTop(zoomItem); } if (!addedLayer && presContext->IsRootContentDocument()) { // We always want top level content documents to be in their own layer. nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer( aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems); childItems.AppendToTop(layerItem); } // Clip children to the child root frame's rectangle rv = aLists.Content()->AppendNewToTop( new (aBuilder) nsDisplayClip(aBuilder, this, &childItems, subdocBoundsInParentUnits)); } // delete childItems in case of OOM childItems.DeleteAll(); if (subdocRootFrame) { aBuilder->LeavePresShell(subdocRootFrame, dirty); } return rv; }