michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // YY need to pass isMultiple before create called michael@0: michael@0: #include "nsBoxFrame.h" michael@0: #include "nsCSSRendering.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsDisplayList.h" michael@0: michael@0: class nsGroupBoxFrame : public nsBoxFrame { michael@0: public: michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: michael@0: nsGroupBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext): michael@0: nsBoxFrame(aShell, aContext) {} michael@0: michael@0: virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding); michael@0: michael@0: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) MOZ_OVERRIDE; michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: virtual nsresult GetFrameName(nsAString& aResult) const { michael@0: return MakeFrameName(NS_LITERAL_STRING("GroupBoxFrame"), aResult); michael@0: } michael@0: #endif michael@0: michael@0: virtual bool HonorPrintBackgroundSettings() { return false; } michael@0: michael@0: void PaintBorderBackground(nsRenderingContext& aRenderingContext, michael@0: nsPoint aPt, const nsRect& aDirtyRect); michael@0: michael@0: // make sure we our kids get our orient and align instead of us. michael@0: // our child box has no content node so it will search for a parent with one. michael@0: // that will be us. michael@0: virtual void GetInitialOrientation(bool& aHorizontal) { aHorizontal = false; } michael@0: virtual bool GetInitialHAlignment(Halignment& aHalign) { aHalign = hAlign_Left; return true; } michael@0: virtual bool GetInitialVAlignment(Valignment& aValign) { aValign = vAlign_Top; return true; } michael@0: virtual bool GetInitialAutoStretch(bool& aStretch) { aStretch = true; return true; } michael@0: michael@0: nsIFrame* GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect); michael@0: }; michael@0: michael@0: /* michael@0: class nsGroupBoxInnerFrame : public nsBoxFrame { michael@0: public: michael@0: michael@0: nsGroupBoxInnerFrame(nsIPresShell* aShell, nsStyleContext* aContext): michael@0: nsBoxFrame(aShell, aContext) {} michael@0: michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: NS_IMETHOD GetFrameName(nsString& aResult) const { michael@0: return MakeFrameName("GroupBoxFrameInner", aResult); michael@0: } michael@0: #endif michael@0: michael@0: // we are always flexible michael@0: virtual bool GetDefaultFlex(int32_t& aFlex) { aFlex = 1; return true; } michael@0: michael@0: }; michael@0: */ michael@0: michael@0: nsIFrame* michael@0: NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsGroupBoxFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame) michael@0: michael@0: class nsDisplayXULGroupBackground : public nsDisplayItem { michael@0: public: michael@0: nsDisplayXULGroupBackground(nsDisplayListBuilder* aBuilder, michael@0: nsGroupBoxFrame* aFrame) : michael@0: nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayXULGroupBackground); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayXULGroupBackground() { michael@0: MOZ_COUNT_DTOR(nsDisplayXULGroupBackground); michael@0: } michael@0: #endif michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) { michael@0: aOutFrames->AppendElement(mFrame); michael@0: } michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx); michael@0: NS_DISPLAY_DECL_NAME("XULGroupBackground", TYPE_XUL_GROUP_BACKGROUND) michael@0: }; michael@0: michael@0: void michael@0: nsDisplayXULGroupBackground::Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx) michael@0: { michael@0: static_cast(mFrame)-> michael@0: PaintBorderBackground(*aCtx, ToReferenceFrame(), mVisibleRect); michael@0: } michael@0: michael@0: void michael@0: nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // Paint our background and border michael@0: if (IsVisibleForPainting(aBuilder)) { michael@0: aLists.BorderBackground()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayXULGroupBackground(aBuilder, this)); michael@0: michael@0: DisplayOutline(aBuilder, aLists); michael@0: } michael@0: michael@0: BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); michael@0: } michael@0: michael@0: void michael@0: nsGroupBoxFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext, michael@0: nsPoint aPt, const nsRect& aDirtyRect) { michael@0: int skipSides = 0; michael@0: const nsStyleBorder* borderStyleData = StyleBorder(); michael@0: const nsMargin& border = borderStyleData->GetComputedBorder(); michael@0: nscoord yoff = 0; michael@0: nsPresContext* presContext = PresContext(); michael@0: michael@0: nsRect groupRect; michael@0: nsIFrame* groupBox = GetCaptionBox(presContext, groupRect); michael@0: michael@0: if (groupBox) { michael@0: // if the border is smaller than the legend. Move the border down michael@0: // to be centered on the legend. michael@0: nsMargin groupMargin; michael@0: groupBox->StyleMargin()->GetMargin(groupMargin); michael@0: groupRect.Inflate(groupMargin); michael@0: michael@0: if (border.top < groupRect.height) michael@0: yoff = (groupRect.height - border.top)/2 + groupRect.y; michael@0: } michael@0: michael@0: nsRect rect(aPt.x, aPt.y + yoff, mRect.width, mRect.height - yoff); michael@0: michael@0: groupRect += aPt; michael@0: michael@0: nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, michael@0: aDirtyRect, rect, michael@0: nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES); michael@0: michael@0: if (groupBox) { michael@0: michael@0: // we should probably use PaintBorderEdges to do this but for now just use clipping michael@0: // to achieve the same effect. michael@0: michael@0: // draw left side michael@0: nsRect clipRect(rect); michael@0: clipRect.width = groupRect.x - rect.x; michael@0: clipRect.height = border.top; michael@0: michael@0: aRenderingContext.PushState(); michael@0: aRenderingContext.IntersectClip(clipRect); michael@0: nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, michael@0: aDirtyRect, rect, mStyleContext, skipSides); michael@0: michael@0: aRenderingContext.PopState(); michael@0: michael@0: michael@0: // draw right side michael@0: clipRect = rect; michael@0: clipRect.x = groupRect.XMost(); michael@0: clipRect.width = rect.XMost() - groupRect.XMost(); michael@0: clipRect.height = border.top; michael@0: michael@0: aRenderingContext.PushState(); michael@0: aRenderingContext.IntersectClip(clipRect); michael@0: nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, michael@0: aDirtyRect, rect, mStyleContext, skipSides); michael@0: michael@0: aRenderingContext.PopState(); michael@0: michael@0: michael@0: michael@0: // draw bottom michael@0: michael@0: clipRect = rect; michael@0: clipRect.y += border.top; michael@0: clipRect.height = mRect.height - (yoff + border.top); michael@0: michael@0: aRenderingContext.PushState(); michael@0: aRenderingContext.IntersectClip(clipRect); michael@0: nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, michael@0: aDirtyRect, rect, mStyleContext, skipSides); michael@0: michael@0: aRenderingContext.PopState(); michael@0: michael@0: } else { michael@0: nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, michael@0: aDirtyRect, nsRect(aPt, GetSize()), michael@0: mStyleContext, skipSides); michael@0: } michael@0: } michael@0: michael@0: nsIFrame* michael@0: nsGroupBoxFrame::GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect) michael@0: { michael@0: // first child is our grouped area michael@0: nsIFrame* box = GetChildBox(); michael@0: michael@0: // no area fail. michael@0: if (!box) michael@0: return nullptr; michael@0: michael@0: // get the first child in the grouped area, that is the caption michael@0: box = box->GetChildBox(); michael@0: michael@0: // nothing in the area? fail michael@0: if (!box) michael@0: return nullptr; michael@0: michael@0: // now get the caption itself. It is in the caption frame. michael@0: nsIFrame* child = box->GetChildBox(); michael@0: michael@0: if (child) { michael@0: // convert to our coordinates. michael@0: nsRect parentRect(box->GetRect()); michael@0: aCaptionRect = child->GetRect(); michael@0: aCaptionRect.x += parentRect.x; michael@0: aCaptionRect.y += parentRect.y; michael@0: } michael@0: michael@0: return child; michael@0: } michael@0: michael@0: nsresult michael@0: nsGroupBoxFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding) michael@0: { michael@0: aBorderAndPadding.SizeTo(0,0,0,0); michael@0: return NS_OK; michael@0: } michael@0: