michael@0: /* -*- Mode: C++; tab-width: 8; 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: // michael@0: // Eric Vaughan michael@0: // Netscape Communications michael@0: // michael@0: // See documentation in associated header file michael@0: // michael@0: michael@0: #include "nsLeafBoxFrame.h" michael@0: #include "nsBoxFrame.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsIContent.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsBoxLayoutState.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsContainerFrame.h" michael@0: #include "nsDisplayList.h" michael@0: #include michael@0: michael@0: // michael@0: // NS_NewLeafBoxFrame michael@0: // michael@0: // Creates a new Toolbar frame and returns it michael@0: // michael@0: nsIFrame* michael@0: NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsLeafBoxFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame) michael@0: michael@0: nsLeafBoxFrame::nsLeafBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext) michael@0: : nsLeafFrame(aContext) michael@0: { michael@0: } michael@0: michael@0: #ifdef DEBUG_LAYOUT michael@0: void michael@0: nsLeafBoxFrame::GetBoxName(nsAutoString& aName) michael@0: { michael@0: GetFrameName(aName); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: /** michael@0: * Initialize us. This is a good time to get the alignment of the box michael@0: */ michael@0: void michael@0: nsLeafBoxFrame::Init( michael@0: nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) michael@0: { michael@0: nsLeafFrame::Init(aContent, aParent, aPrevInFlow); michael@0: michael@0: if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { michael@0: AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); michael@0: } michael@0: michael@0: UpdateMouseThrough(); michael@0: } michael@0: michael@0: nsresult michael@0: nsLeafBoxFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: nsresult rv = nsLeafFrame::AttributeChanged(aNameSpaceID, aAttribute, michael@0: aModType); michael@0: michael@0: if (aAttribute == nsGkAtoms::mousethrough) michael@0: UpdateMouseThrough(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void nsLeafBoxFrame::UpdateMouseThrough() michael@0: { michael@0: if (mContent) { michael@0: static nsIContent::AttrValuesArray strings[] = michael@0: {&nsGkAtoms::never, &nsGkAtoms::always, nullptr}; michael@0: switch (mContent->FindAttrValueIn(kNameSpaceID_None, michael@0: nsGkAtoms::mousethrough, michael@0: strings, eCaseMatters)) { michael@0: case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break; michael@0: case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break; michael@0: case 2: { michael@0: RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); michael@0: RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsLeafBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // REVIEW: GetFrameForPoint used to not report events for the background michael@0: // layer, whereas this code will put an event receiver for this frame in the michael@0: // BlockBorderBackground() list. But I don't see any need to preserve michael@0: // that anomalous behaviour. The important thing I'm preserving is that michael@0: // leaf boxes continue to receive events in the foreground layer. michael@0: DisplayBorderBackgroundOutline(aBuilder, aLists); michael@0: michael@0: if (!aBuilder->IsForEventDelivery() || !IsVisibleForPainting(aBuilder)) michael@0: return; michael@0: michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayEventReceiver(aBuilder, this)); michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsLeafBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result; michael@0: DISPLAY_MIN_WIDTH(this, result); michael@0: nsBoxLayoutState state(PresContext(), aRenderingContext); michael@0: nsSize minSize = GetMinSize(state); michael@0: michael@0: // GetMinSize returns border-box width, and we want to return content michael@0: // width. Since Reflow uses the reflow state's border and padding, we michael@0: // actually just want to subtract what GetMinSize added, which is the michael@0: // result of GetBorderAndPadding. michael@0: nsMargin bp; michael@0: GetBorderAndPadding(bp); michael@0: michael@0: result = minSize.width - bp.LeftRight(); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsLeafBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result; michael@0: DISPLAY_PREF_WIDTH(this, result); michael@0: nsBoxLayoutState state(PresContext(), aRenderingContext); michael@0: nsSize prefSize = GetPrefSize(state); michael@0: michael@0: // GetPrefSize returns border-box width, and we want to return content michael@0: // width. Since Reflow uses the reflow state's border and padding, we michael@0: // actually just want to subtract what GetPrefSize added, which is the michael@0: // result of GetBorderAndPadding. michael@0: nsMargin bp; michael@0: GetBorderAndPadding(bp); michael@0: michael@0: result = prefSize.width - bp.LeftRight(); michael@0: michael@0: return result; michael@0: } michael@0: michael@0: nscoord michael@0: nsLeafBoxFrame::GetIntrinsicWidth() michael@0: { michael@0: // No intrinsic width michael@0: return 0; michael@0: } michael@0: michael@0: nsSize michael@0: nsLeafBoxFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, michael@0: nsSize aCBSize, nscoord aAvailableWidth, michael@0: nsSize aMargin, nsSize aBorder, michael@0: nsSize aPadding, bool aShrinkWrap) michael@0: { michael@0: // Important: NOT calling our direct superclass here! michael@0: return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth, michael@0: aMargin, aBorder, aPadding, aShrinkWrap); michael@0: } michael@0: michael@0: nsresult michael@0: nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: // This is mostly a copy of nsBoxFrame::Reflow(). michael@0: // We aren't able to share an implementation because of the frame michael@0: // class hierarchy. If you make changes here, please keep michael@0: // nsBoxFrame::Reflow in sync. michael@0: michael@0: DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame"); michael@0: DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); michael@0: michael@0: NS_ASSERTION(aReflowState.ComputedWidth() >=0 && michael@0: aReflowState.ComputedHeight() >= 0, "Computed Size < 0"); michael@0: michael@0: #ifdef DO_NOISY_REFLOW michael@0: printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n"); michael@0: printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++); michael@0: switch (aReflowState.reason) { michael@0: case eReflowReason_Initial: michael@0: printf("Ini");break; michael@0: case eReflowReason_Incremental: michael@0: printf("Inc");break; michael@0: case eReflowReason_Resize: michael@0: printf("Rsz");break; michael@0: case eReflowReason_StyleChange: michael@0: printf("Sty");break; michael@0: case eReflowReason_Dirty: michael@0: printf("Drt "); michael@0: break; michael@0: default:printf("%d", aReflowState.reason);break; michael@0: } michael@0: michael@0: printSize("AW", aReflowState.AvailableWidth()); michael@0: printSize("AH", aReflowState.AvailableHeight()); michael@0: printSize("CW", aReflowState.ComputedWidth()); michael@0: printSize("CH", aReflowState.ComputedHeight()); michael@0: michael@0: printf(" *\n"); michael@0: michael@0: #endif michael@0: michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: michael@0: // create the layout state michael@0: nsBoxLayoutState state(aPresContext, aReflowState.rendContext); michael@0: michael@0: nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight()); michael@0: michael@0: nsMargin m; michael@0: m = aReflowState.ComputedPhysicalBorderPadding(); michael@0: michael@0: //GetBorderAndPadding(m); michael@0: michael@0: // this happens sometimes. So lets handle it gracefully. michael@0: if (aReflowState.ComputedHeight() == 0) { michael@0: nsSize minSize = GetMinSize(state); michael@0: computedSize.height = minSize.height - m.top - m.bottom; michael@0: } michael@0: michael@0: nsSize prefSize(0,0); michael@0: michael@0: // if we are told to layout intrinic then get our preferred size. michael@0: if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) { michael@0: prefSize = GetPrefSize(state); michael@0: nsSize minSize = GetMinSize(state); michael@0: nsSize maxSize = GetMaxSize(state); michael@0: prefSize = BoundsCheck(minSize, prefSize, maxSize); michael@0: } michael@0: michael@0: // get our desiredSize michael@0: if (aReflowState.ComputedWidth() == NS_INTRINSICSIZE) { michael@0: computedSize.width = prefSize.width; michael@0: } else { michael@0: computedSize.width += m.left + m.right; michael@0: } michael@0: michael@0: if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) { michael@0: computedSize.height = prefSize.height; michael@0: } else { michael@0: computedSize.height += m.top + m.bottom; michael@0: } michael@0: michael@0: // handle reflow state min and max sizes michael@0: // XXXbz the width handling here seems to be wrong, since michael@0: // mComputedMin/MaxWidth is a content-box size, whole michael@0: // computedSize.width is a border-box size... michael@0: if (computedSize.width > aReflowState.ComputedMaxWidth()) michael@0: computedSize.width = aReflowState.ComputedMaxWidth(); michael@0: michael@0: if (computedSize.width < aReflowState.ComputedMinWidth()) michael@0: computedSize.width = aReflowState.ComputedMinWidth(); michael@0: michael@0: // Now adjust computedSize.height for our min and max computed michael@0: // height. The only problem is that those are content-box sizes, michael@0: // while computedSize.height is a border-box size. So subtract off michael@0: // m.TopBottom() before adjusting, then readd it. michael@0: computedSize.height = std::max(0, computedSize.height - m.TopBottom()); michael@0: computedSize.height = NS_CSS_MINMAX(computedSize.height, michael@0: aReflowState.ComputedMinHeight(), michael@0: aReflowState.ComputedMaxHeight()); michael@0: computedSize.height += m.TopBottom(); michael@0: michael@0: nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height); michael@0: michael@0: SetBounds(state, r); michael@0: michael@0: // layout our children michael@0: Layout(state); michael@0: michael@0: // ok our child could have gotten bigger. So lets get its bounds michael@0: aDesiredSize.Width() = mRect.width; michael@0: aDesiredSize.Height() = mRect.height; michael@0: aDesiredSize.SetTopAscent(GetBoxAscent(state)); michael@0: michael@0: // the overflow rect is set in SetBounds() above michael@0: aDesiredSize.mOverflowAreas = GetOverflowAreas(); michael@0: michael@0: #ifdef DO_NOISY_REFLOW michael@0: { michael@0: printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height()); michael@0: michael@0: if (maxElementWidth) { michael@0: printf("MW:%d\n", *maxElementWidth); michael@0: } else { michael@0: printf("MW:?\n"); michael@0: } michael@0: michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: nsresult michael@0: nsLeafBoxFrame::GetFrameName(nsAString& aResult) const michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult); michael@0: } michael@0: #endif michael@0: michael@0: nsIAtom* michael@0: nsLeafBoxFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::leafBoxFrame; michael@0: } michael@0: michael@0: nsresult michael@0: nsLeafBoxFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) michael@0: { michael@0: MarkIntrinsicWidthsDirty(); michael@0: return nsLeafFrame::CharacterDataChanged(aInfo); michael@0: } michael@0: michael@0: /* virtual */ nsSize michael@0: nsLeafBoxFrame::GetPrefSize(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::GetPrefSize(aState); michael@0: } michael@0: michael@0: /* virtual */ nsSize michael@0: nsLeafBoxFrame::GetMinSize(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::GetMinSize(aState); michael@0: } michael@0: michael@0: /* virtual */ nsSize michael@0: nsLeafBoxFrame::GetMaxSize(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::GetMaxSize(aState); michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsLeafBoxFrame::GetFlex(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::GetFlex(aState); michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: nsLeafBoxFrame::GetBoxAscent(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::GetBoxAscent(aState); michael@0: } michael@0: michael@0: /* virtual */ void michael@0: nsLeafBoxFrame::MarkIntrinsicWidthsDirty() michael@0: { michael@0: // Don't call base class method, since everything it does is within an michael@0: // IsBoxWrapped check. michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsLeafBoxFrame::DoLayout(nsBoxLayoutState& aState) michael@0: { michael@0: return nsBox::DoLayout(aState); michael@0: }