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