/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ #include "nsMathMLSelectedFrame.h" #include "nsDisplayList.h" using namespace mozilla; nsMathMLSelectedFrame::~nsMathMLSelectedFrame() = default; NS_IMETHODIMP nsMathMLSelectedFrame::TransmitAutomaticData() { // Note that to determine space-like and embellished op properties: // - behaves the same as // - behaves the same as // The REC defines the following element to be space-like: // * an maction element whose selected sub-expression exists and is // space-like; nsIMathMLFrame* mathMLFrame = do_QueryFrame(mSelectedFrame); if (mathMLFrame && mathMLFrame->IsSpaceLike()) { mPresentationData.flags |= NS_MATHML_SPACE_LIKE; } else { mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE; } // The REC defines the following element to be an embellished operator: // * an maction element whose selected sub-expression exists and is an // embellished operator; mPresentationData.baseFrame = mSelectedFrame; GetEmbellishDataFrom(mSelectedFrame, mEmbellishData); return NS_OK; } nsresult nsMathMLSelectedFrame::ChildListChanged(int32_t aModType) { GetSelectedFrame(); return nsMathMLContainerFrame::ChildListChanged(aModType); } void nsMathMLSelectedFrame::SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) { nsMathMLContainerFrame::SetInitialChildList(aListID, std::move(aChildList)); // This very first call to GetSelectedFrame() will cause us to be marked as an // embellished operator if the selected child is an embellished operator GetSelectedFrame(); } // Only paint the selected child... void nsMathMLSelectedFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { // Report an error if something wrong was found in this frame. // We can't call nsDisplayMathMLError from here, // so ask nsMathMLContainerFrame to do the work for us. if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) { nsMathMLContainerFrame::BuildDisplayList(aBuilder, aLists); return; } DisplayBorderBackgroundOutline(aBuilder, aLists); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { // Put the child's background directly onto the content list nsDisplayListSet set(aLists, aLists.Content()); // The children should be in content order BuildDisplayListForChild(aBuilder, childFrame, set); } #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX) // visual debug DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists); #endif } /* virtual */ nsIFrame::SizeComputationResult nsMathMLSelectedFrame::ComputeSize( gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize, nscoord aAvailableISize, const LogicalSize& aMargin, const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) { nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { // Delegate size computation to the child frame. // Try to account for border/padding/margin on this frame and the child, // though we don't really support them during reflow anyway... const nscoord availableISize = aAvailableISize - aBorderPadding.ISize(aWM) - aMargin.ISize(aWM); const LogicalSize cbSize = aCBSize - aBorderPadding - aMargin; SizeComputationInput offsetState(childFrame, aRenderingContext, aWM, availableISize); const auto bpSize = offsetState.ComputedLogicalBorderPadding(aWM).Size(aWM); auto size = childFrame->ComputeSize( aRenderingContext, aWM, cbSize, availableISize, offsetState.ComputedLogicalMargin(aWM).Size(aWM), bpSize, aSizeOverrides, aFlags); return {size.mLogicalSize + bpSize, size.mAspectRatioUsage}; } return {LogicalSize(aWM), AspectRatioUsage::None}; } // Only reflow the selected child ... void nsMathMLSelectedFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); mPresentationData.flags &= ~NS_MATHML_ERROR; aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); nsIFrame* childFrame = GetSelectedFrame(); if (childFrame) { WritingMode wm = childFrame->GetWritingMode(); LogicalSize availSize = aReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame, availSize); ReflowChild(childFrame, aPresContext, aDesiredSize, childReflowInput, aStatus); SaveReflowAndBoundingMetricsFor(childFrame, aDesiredSize, aDesiredSize.mBoundingMetrics); mBoundingMetrics = aDesiredSize.mBoundingMetrics; } FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize); } // Only place the selected child ... /* virtual */ nsresult nsMathMLSelectedFrame::Place(DrawTarget* aDrawTarget, bool aPlaceOrigin, ReflowOutput& aDesiredSize) { nsIFrame* childFrame = GetSelectedFrame(); if (mInvalidMarkup) { // Calling PlaceForError when mathml.error_message_layout_for_invalid_markup // is disabled causes assertion failures because nsMathMLSelectedFrame only // performs layout of the selected child. However, this code is only reached // when mathml.legacy_maction_and_semantics_implementations is enabled, so // it is out the scope of the mrow fallback described in MathML Core and // nsMathMLSelectedFrame will go away in the future. So for now let's // continue to always layout this case as an 'invalid-markup' message. return ReflowError(aDrawTarget, aDesiredSize); } aDesiredSize.ClearSize(); aDesiredSize.SetBlockStartAscent(0); mBoundingMetrics = nsBoundingMetrics(); if (childFrame) { GetReflowAndBoundingMetricsFor(childFrame, aDesiredSize, mBoundingMetrics); if (aPlaceOrigin) { FinishReflowChild(childFrame, PresContext(), aDesiredSize, nullptr, 0, 0, ReflowChildFlags::Default); } mReference.x = 0; mReference.y = aDesiredSize.BlockStartAscent(); } aDesiredSize.mBoundingMetrics = mBoundingMetrics; return NS_OK; }