Bug 1428701 - (Part 1) Build the dropdown frame as the top layer frame in the viewport frame
When a dropdown frame is toggled to drop down, we set it to its parent,
the canvas frame. If it's toggled to roll up, we clear the dropdown
frame in the canvas frame.
Then we build the display lists of the dropdown frame that should be
dropped down after building the other top layer contents to make sure
that the dropdown frame would be on the top of all contents.
MozReview-Commit-ID: AouhRY1ma13
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -177,16 +177,21 @@ ViewportFrame::BuildDisplayListForTopLay
BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, aList);
}
BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
}
}
nsIPresShell* shell = PresShell();
if (nsCanvasFrame* canvasFrame = shell->GetCanvasFrame()) {
+ // Build display items for the dropped-down menu
+ if (nsIFrame* dropdownFrame = canvasFrame->GetDropdownFrame()) {
+ BuildDisplayListForTopLayerFrame(aBuilder, dropdownFrame, aList);
+ }
+
if (Element* container = canvasFrame->GetCustomContentContainer()) {
if (nsIFrame* frame = container->GetPrimaryFrame()) {
BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
}
}
}
}
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -251,16 +251,25 @@ nsRect nsCanvasFrame::CanvasArea() const
if (scrollableFrame) {
nsRect portRect = scrollableFrame->GetScrollPortRect();
result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size()));
}
return result;
}
void
+nsCanvasFrame::SetDropdownFrame(nsIFrame* aDropdownFrame) {
+ if (aDropdownFrame) {
+ MOZ_ASSERT(aDropdownFrame->IsListControlFrame(),
+ "Only nsListControlFrame can be dropped down.");
+ }
+ mDropdownFrame = aDropdownFrame;
+}
+
+void
nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx)
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
nsPoint offset = ToReferenceFrame();
nsRect bgClipRect = frame->CanvasArea() + offset;
if (NS_GET_A(mColor) > 0) {
DrawTarget* drawTarget = aCtx->GetDrawTarget();
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -33,16 +33,17 @@ class nsCanvasFrame final : public nsCon
public nsIScrollPositionListener,
public nsIAnonymousContentCreator
{
public:
explicit nsCanvasFrame(nsStyleContext* aContext)
: nsContainerFrame(aContext, kClassID)
, mDoPaintFocus(false)
, mAddedScrollPositionListener(false)
+ , mDropdownFrame(nullptr)
{}
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsCanvasFrame)
virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
@@ -108,26 +109,33 @@ public:
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override;
#endif
virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
nsIContent** aContent) override;
nsRect CanvasArea() const;
+ // The frame should be dropped down
+ nsIFrame* GetDropdownFrame() const { return mDropdownFrame; }
+ void SetDropdownFrame(nsIFrame* aDropDownFrame);
+
protected:
// Utility function to propagate the WritingMode from our first child to
// 'this' and all its ancestors.
void MaybePropagateRootElementWritingMode();
// Data members
bool mDoPaintFocus;
bool mAddedScrollPositionListener;
nsCOMPtr<mozilla::dom::Element> mCustomContentContainer;
+
+private:
+ nsIFrame* mDropdownFrame;
};
/**
* Override nsDisplayBackground methods so that we pass aBGClipRect to
* PaintBackground, covering the whole overflow area.
* We can also paint an "extra background color" behind the normal
* background.
*/