コード例 #1
0
void
nsRangeFrame::ReflowAnonymousContent(nsPresContext*           aPresContext,
                                     nsHTMLReflowMetrics&     aDesiredSize,
                                     const nsHTMLReflowState& aReflowState)
{
  // The width/height of our content box, which is the available width/height
  // for our anonymous content:
  nscoord rangeFrameContentBoxWidth = aReflowState.ComputedWidth();
  nscoord rangeFrameContentBoxHeight = aReflowState.ComputedHeight();
  if (rangeFrameContentBoxHeight == NS_AUTOHEIGHT) {
    rangeFrameContentBoxHeight = 0;
  }

  nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();

  if (trackFrame) { // display:none?

    // Position the track:
    // The idea here is that we allow content authors to style the width,
    // height, border and padding of the track, but we ignore margin and
    // positioning properties and do the positioning ourself to keep the center
    // of the track's border box on the center of the nsRangeFrame's content
    // box.

    WritingMode wm = trackFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState trackReflowState(aPresContext, aReflowState,
                                       trackFrame, availSize);

    // Find the x/y position of the track frame such that it will be positioned
    // as described above. These coordinates are with respect to the
    // nsRangeFrame's border-box.
    nscoord trackX = rangeFrameContentBoxWidth / 2;
    nscoord trackY = rangeFrameContentBoxHeight / 2;

    // Account for the track's border and padding (we ignore its margin):
    trackX -= trackReflowState.ComputedPhysicalBorderPadding().left +
                trackReflowState.ComputedWidth() / 2;
    trackY -= trackReflowState.ComputedPhysicalBorderPadding().top +
                trackReflowState.ComputedHeight() / 2;

    // Make relative to our border box instead of our content box:
    trackX += aReflowState.ComputedPhysicalBorderPadding().left;
    trackY += aReflowState.ComputedPhysicalBorderPadding().top;

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics trackDesiredSize(aReflowState);
    ReflowChild(trackFrame, aPresContext, trackDesiredSize,
                trackReflowState, trackX, trackY, 0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(trackFrame, aPresContext, trackDesiredSize,
                      &trackReflowState, trackX, trackY, 0);
  }

  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();

  if (thumbFrame) { // display:none?
    WritingMode wm = thumbFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState thumbReflowState(aPresContext, aReflowState,
                                       thumbFrame, availSize);

    // Where we position the thumb depends on its size, so we first reflow
    // the thumb at {0,0} to obtain its size, then position it afterwards.

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics thumbDesiredSize(aReflowState);
    ReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
                thumbReflowState, 0, 0, 0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
                      &thumbReflowState, 0, 0, 0);
    DoUpdateThumbPosition(thumbFrame, nsSize(aDesiredSize.Width(),
                                             aDesiredSize.Height()));
  }

  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();

  if (rangeProgressFrame) { // display:none?
    WritingMode wm = rangeProgressFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState progressReflowState(aPresContext, aReflowState,
                                          rangeProgressFrame, availSize);

    // We first reflow the range-progress frame at {0,0} to obtain its
    // unadjusted dimensions, then we adjust it to so that the appropriate edge
    // ends at the thumb.

    nsReflowStatus frameStatus;
    nsHTMLReflowMetrics progressDesiredSize(aReflowState);
    ReflowChild(rangeProgressFrame, aPresContext,
                progressDesiredSize, progressReflowState, 0, 0,
                0, frameStatus);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
               "We gave our child unconstrained height, so it should be complete");
    FinishReflowChild(rangeProgressFrame, aPresContext,
                      progressDesiredSize, &progressReflowState, 0, 0, 0);
    DoUpdateRangeProgressFrame(rangeProgressFrame, nsSize(aDesiredSize.Width(),
                                                          aDesiredSize.Height()));
  }
}
コード例 #2
0
ファイル: nsInlineFrame.cpp プロジェクト: xfosdev/OpenFox
nsresult
nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
                            const nsHTMLReflowState& aReflowState,
                            InlineReflowState& irs,
                            nsHTMLReflowMetrics& aMetrics,
                            nsReflowStatus& aStatus)
{
  nsresult rv = NS_OK;
  aStatus = NS_FRAME_COMPLETE;

  nsLineLayout* lineLayout = aReflowState.mLineLayout;
  bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
  RestyleManager* restyleManager = aPresContext->RestyleManager();
  bool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
  nscoord leftEdge = 0;
  // Don't offset by our start borderpadding if we have a prev continuation or
  // if we're in a part of an {ib} split other than the first one.
  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
    leftEdge = ltr ? aReflowState.ComputedPhysicalBorderPadding().left
                   : aReflowState.ComputedPhysicalBorderPadding().right;
  }
  nscoord availableWidth = aReflowState.AvailableWidth();
  NS_ASSERTION(availableWidth != NS_UNCONSTRAINEDSIZE,
               "should no longer use available widths");
  // Subtract off left and right border+padding from availableWidth
  availableWidth -= leftEdge;
  availableWidth -= ltr ? aReflowState.ComputedPhysicalBorderPadding().right
                        : aReflowState.ComputedPhysicalBorderPadding().left;
  lineLayout->BeginSpan(this, &aReflowState, leftEdge,
                        leftEdge + availableWidth, &mBaseline);

  // First reflow our principal children.
  nsIFrame* frame = mFrames.FirstChild();
  bool done = false;
  while (frame) {
    // Check if we should lazily set the child frame's parent pointer.
    if (irs.mSetParentPointer) {
      bool havePrevBlock =
        irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
      nsIFrame* child = frame;
      do {
        // If our block is the first in flow, then any floats under the pulled
        // frame must already belong to our block.
        if (havePrevBlock) {
          // This has to happen before we update frame's parent; we need to
          // know frame's ancestry under its old block.
          // The blockChildren.ContainsFrame check performed by
          // ReparentFloatsForInlineChild here may be slow, but we can't
          // easily avoid it because we don't know where 'frame' originally
          // came from. If we really really have to optimize this we could
          // cache whether frame->GetParent() is under its containing blocks
          // overflowList or not.
          ReparentFloatsForInlineChild(irs.mLineContainer, child, false);
        }
        child->SetParent(this);
        if (inFirstLine) {
          restyleManager->ReparentStyleContext(child);
        }
        // We also need to do the same for |frame|'s next-in-flows that are in
        // the sibling list. Otherwise, if we reflow |frame| and it's complete
        // we'll crash when trying to delete its next-in-flow.
        // This scenario doesn't happen often, but it can happen.
        nsIFrame* nextSibling = child->GetNextSibling();
        child = child->GetNextInFlow();
        if (MOZ_UNLIKELY(child)) {
          while (child != nextSibling && nextSibling) {
            nextSibling = nextSibling->GetNextSibling();
          }
          if (!nextSibling) {
            child = nullptr;
          }
        }
        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
      } while (child);

      // Fix the parent pointer for ::first-letter child frame next-in-flows,
      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
      if (realFrame->GetType() == nsGkAtoms::letterFrame) {
        nsIFrame* child = realFrame->GetFirstPrincipalChild();
        if (child) {
          NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
                       "unexpected frame type");
          nsIFrame* nextInFlow = child->GetNextInFlow();
          for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
            NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame,
                         "unexpected frame type");
            if (mFrames.ContainsFrame(nextInFlow)) {
              nextInFlow->SetParent(this);
              if (inFirstLine) {
                restyleManager->ReparentStyleContext(nextInFlow);
              }
            }
            else {
#ifdef DEBUG              
              // Once we find a next-in-flow that isn't ours none of the
              // remaining next-in-flows should be either.
              for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
                             "unexpected letter frame flow");
              }
#endif
              break;
            }
          }
        }
      }
    }
    MOZ_ASSERT(frame->GetParent() == this);

    if (!done) {
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
      done = NS_FAILED(rv) ||
             NS_INLINE_IS_BREAK(aStatus) || 
             (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus));
      if (done) {
        if (!irs.mSetParentPointer) {
          break;
        }
        // Keep reparenting the remaining siblings, but don't reflow them.
        nsFrameList* pushedFrames = GetOverflowFrames();
        if (pushedFrames && pushedFrames->FirstChild() == frame) {
          // Don't bother if |frame| was pushed to our overflow list.
          break;
        }
      } else {
        irs.mPrevFrame = frame;
      }
    }
    frame = frame->GetNextSibling();
  }

  // Attempt to pull frames from our next-in-flow until we can't
  if (!done && GetNextInFlow()) {
    while (true) {
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
      bool isComplete;
      if (!frame) { // Could be non-null if we pulled a first-letter frame and
                    // it created a continuation, since we don't push those.
        frame = PullOneFrame(aPresContext, irs, &isComplete);
      }
#ifdef NOISY_PUSHING
      printf("%p pulled up %p\n", this, frame);
#endif
      if (nullptr == frame) {
        if (!isComplete) {
          aStatus = NS_FRAME_NOT_COMPLETE;
        }
        break;
      }
      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
      if (NS_FAILED(rv) ||
          NS_INLINE_IS_BREAK(aStatus) || 
          (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
        break;
      }
      irs.mPrevFrame = frame;
      frame = frame->GetNextSibling();
    }
  }

  NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) || !GetOverflowFrames(),
               "We can't be complete AND have overflow frames!");

  // If after reflowing our children they take up no area then make
  // sure that we don't either.
  //
  // Note: CSS demands that empty inline elements still affect the
  // line-height calculations. However, continuations of an inline
  // that are empty we force to empty so that things like collapsed
  // whitespace in an inline element don't affect the line-height.
  aMetrics.Width() = lineLayout->EndSpan(this);

  // Compute final width.

  // Make sure to not include our start border and padding if we have a prev
  // continuation or if we're in a part of an {ib} split other than the first
  // one.
  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
    aMetrics.Width() += ltr ? aReflowState.ComputedPhysicalBorderPadding().left
                          : aReflowState.ComputedPhysicalBorderPadding().right;
  }

  /*
   * We want to only apply the end border and padding if we're the last
   * continuation and either not in an {ib} split or the last part of it.  To
   * be the last continuation we have to be complete (so that we won't get a
   * next-in-flow) and have no non-fluid continuations on our continuation
   * chain.
   */
  if (NS_FRAME_IS_COMPLETE(aStatus) &&
      !LastInFlow()->GetNextContinuation() &&
      !FrameIsNonLastInIBSplit()) {
    aMetrics.Width() += ltr ? aReflowState.ComputedPhysicalBorderPadding().right
                          : aReflowState.ComputedPhysicalBorderPadding().left;
  }

  nsRefPtr<nsFontMetrics> fm;
  float inflation = nsLayoutUtils::FontSizeInflationFor(this);
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
  aReflowState.rendContext->SetFont(fm);

  if (fm) {
    // Compute final height of the frame.
    //
    // Do things the standard css2 way -- though it's hard to find it
    // in the css2 spec! It's actually found in the css1 spec section
    // 4.4 (you will have to read between the lines to really see
    // it).
    //
    // The height of our box is the sum of our font size plus the top
    // and bottom border and padding. The height of children do not
    // affect our height.
    aMetrics.SetTopAscent(fm->MaxAscent());
    aMetrics.Height() = fm->MaxHeight();
  } else {
    NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
    aMetrics.SetTopAscent(aMetrics.Height() = 0);
  }
  aMetrics.SetTopAscent(aMetrics.TopAscent() + aReflowState.ComputedPhysicalBorderPadding().top);
  aMetrics.Height() += aReflowState.ComputedPhysicalBorderPadding().top +
    aReflowState.ComputedPhysicalBorderPadding().bottom;

  // For now our overflow area is zero. The real value will be
  // computed in |nsLineLayout::RelativePositionFrames|.
  aMetrics.mOverflowAreas.Clear();

#ifdef NOISY_FINAL_SIZE
  ListTag(stdout);
  printf(": metrics=%d,%d ascent=%d\n",
         aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent());
#endif

  return rv;
}
コード例 #3
0
void
nsSVGOuterSVGFrame::Reflow(nsPresContext*           aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsSVGOuterSVGFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                  ("enter nsSVGOuterSVGFrame::Reflow: availSize=%d,%d",
                  aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));

  NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");

  aStatus = NS_FRAME_COMPLETE;

  aDesiredSize.Width()  = aReflowState.ComputedWidth() +
                          aReflowState.ComputedPhysicalBorderPadding().LeftRight();
  aDesiredSize.Height() = aReflowState.ComputedHeight() +
                          aReflowState.ComputedPhysicalBorderPadding().TopBottom();

  NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages.");

  SVGSVGElement *svgElem = static_cast<SVGSVGElement*>(mContent);

  nsSVGOuterSVGAnonChildFrame *anonKid =
    static_cast<nsSVGOuterSVGAnonChildFrame*>(GetFirstPrincipalChild());

  if (mState & NS_FRAME_FIRST_REFLOW) {
    // Initialize
    svgElem->UpdateHasChildrenOnlyTransform();
  }

  // If our SVG viewport has changed, update our content and notify.
  // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace

  svgFloatSize newViewportSize(
    nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedWidth()),
    nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedHeight()));

  svgFloatSize oldViewportSize = svgElem->GetViewportSize();

  uint32_t changeBits = 0;
  if (newViewportSize != oldViewportSize) {
    // When our viewport size changes, we may need to update the overflow rects
    // of our child frames. This is the case if:
    //
    //  * We have a real/synthetic viewBox (a children-only transform), since
    //    the viewBox transform will change as the viewport dimensions change.
    //
    //  * We do not have a real/synthetic viewBox, but the last time we
    //    reflowed (or the last time UpdateOverflow() was called) we did.
    //
    // We only handle the former case here, in which case we mark all our child
    // frames as dirty so that we reflow them below and update their overflow
    // rects.
    //
    // In the latter case, updating of overflow rects is handled for removal of
    // real viewBox (the viewBox attribute) in AttributeChanged. Synthetic
    // viewBox "removal" (e.g. a document references the same SVG via both an
    // <svg:image> and then as a CSS background image (a synthetic viewBox is
    // used when painting the former, but not when painting the latter)) is
    // handled in SVGSVGElement::FlushImageTransformInvalidation.
    //
    if (svgElem->HasViewBoxOrSyntheticViewBox()) {
      nsIFrame* anonChild = GetFirstPrincipalChild();
      anonChild->AddStateBits(NS_FRAME_IS_DIRTY);
      for (nsIFrame* child = anonChild->GetFirstPrincipalChild(); child;
           child = child->GetNextSibling()) {
        child->AddStateBits(NS_FRAME_IS_DIRTY);
      }
    }
    changeBits |= COORD_CONTEXT_CHANGED;
    svgElem->SetViewportSize(newViewportSize);
  }
  if (mFullZoom != PresContext()->GetFullZoom()) {
    changeBits |= FULL_ZOOM_CHANGED;
    mFullZoom = PresContext()->GetFullZoom();
  }
  if (changeBits) {
    NotifyViewportOrTransformChanged(changeBits);
  }
  mViewportInitialized = true;

  // Now that we've marked the necessary children as dirty, call
  // ReflowSVG() or ReflowSVGNonDisplayText() on them, depending
  // on whether we are non-display.
  mCallingReflowSVG = true;
  if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
    ReflowSVGNonDisplayText(this);
  } else {
    // Update the mRects and visual overflow rects of all our descendants,
    // including our anonymous wrapper kid:
    anonKid->AddStateBits(mState & NS_FRAME_IS_DIRTY);
    anonKid->ReflowSVG();
    NS_ABORT_IF_FALSE(!anonKid->GetNextSibling(),
      "We should have one anonymous child frame wrapping our real children");
  }
  mCallingReflowSVG = false;

  // Set our anonymous kid's offset from our border box:
  anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft());

  // Including our size in our overflow rects regardless of the value of
  // 'background', 'border', etc. makes sure that we usually (when we clip to
  // our content area) don't have to keep changing our overflow rects as our
  // descendants move about (see perf comment below). Including our size in our
  // scrollable overflow rect also makes sure that we scroll if we're too big
  // for our viewport.
  //
  // <svg> never allows scrolling to anything outside its mRect (only panning),
  // so we must always keep our scrollable overflow set to our size.
  //
  // With regards to visual overflow, we always clip root-<svg> (see our
  // BuildDisplayList method) regardless of the value of the 'overflow'
  // property since that is per-spec, even for the initial 'visible' value. For
  // that reason there's no point in adding descendant visual overflow to our
  // own when this frame is for a root-<svg>. That said, there's also a very
  // good performance reason for us wanting to avoid doing so. If we did, then
  // the frame's overflow would often change as descendants that are partially
  // or fully outside its rect moved (think animation on/off screen), and that
  // would cause us to do a full NS_FRAME_IS_DIRTY reflow and repaint of the
  // entire document tree each such move (see bug 875175).
  //
  // So it's only non-root outer-<svg> that has the visual overflow of its
  // descendants added to its own. (Note that the default user-agent style
  // sheet makes 'hidden' the default value for :not(root(svg)), so usually
  // FinishAndStoreOverflow will still clip this back to the frame's rect.)
  //
  // WARNING!! Keep UpdateBounds below in sync with whatever we do for our
  // overflow rects here! (Again, see bug 875175.)
  //
  aDesiredSize.SetOverflowAreasToDesiredBounds();
  if (!mIsRootContent) {
    aDesiredSize.mOverflowAreas.VisualOverflow().UnionRect(
      aDesiredSize.mOverflowAreas.VisualOverflow(),
      anonKid->GetVisualOverflowRect() + anonKid->GetPosition());
  }
  FinishAndStoreOverflow(&aDesiredSize);

  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                  ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
                  aDesiredSize.Width(), aDesiredSize.Height()));
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
コード例 #4
0
/* virtual */ nsresult
nsMathMLmpaddedFrame::Place(nsRenderingContext& aRenderingContext,
                            bool                 aPlaceOrigin,
                            nsHTMLReflowMetrics& aDesiredSize)
{
  nsresult rv =
    nsMathMLContainerFrame::Place(aRenderingContext, false, aDesiredSize);
  if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
    DidReflowChildren(GetFirstPrincipalChild());
    return rv;
  }

  nscoord height = aDesiredSize.TopAscent();
  nscoord depth  = aDesiredSize.Height() - aDesiredSize.TopAscent();
  // The REC says:
  //
  // "The lspace attribute ('leading' space) specifies the horizontal location
  // of the positioning point of the child content with respect to the
  // positioning point of the mpadded element. By default they coincide, and
  // therefore absolute values for lspace have the same effect as relative
  // values."
  //
  // "MathML renderers should ensure that, except for the effects of the
  // attributes, the relative spacing between the contents of the mpadded
  // element and surrounding MathML elements would not be modified by replacing
  // an mpadded element with an mrow element with the same content, even if
  // linebreaking occurs within the mpadded element."
  //
  // (http://www.w3.org/TR/MathML/chapter3.html#presm.mpadded)
  // 
  // "In those discussions, the terms leading and trailing are used to specify
  // a side of an object when which side to use depends on the directionality;
  // ie. leading means left in LTR but right in RTL."
  // (http://www.w3.org/TR/MathML/chapter3.html#presm.bidi.math)
  nscoord lspace = 0;
  // In MathML3, "width" will be the bounding box width and "advancewidth" will
  // refer "to the horizontal distance between the positioning point of the
  // mpadded and the positioning point for the following content".  MathML2
  // doesn't make the distinction.
  nscoord width  = aDesiredSize.Width();
  nscoord voffset = 0;

  int32_t pseudoUnit;
  nscoord initialWidth = width;

  // update width
  pseudoUnit = (mWidthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
             ? NS_MATHML_PSEUDO_UNIT_WIDTH : mWidthPseudoUnit;
  UpdateValue(mWidthSign, pseudoUnit, mWidth,
              aDesiredSize, width);
  width = std::max(0, width);

  // update "height" (this is the ascent in the terminology of the REC)
  pseudoUnit = (mHeightPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
             ? NS_MATHML_PSEUDO_UNIT_HEIGHT : mHeightPseudoUnit;
  UpdateValue(mHeightSign, pseudoUnit, mHeight,
              aDesiredSize, height);
  height = std::max(0, height);

  // update "depth" (this is the descent in the terminology of the REC)
  pseudoUnit = (mDepthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
             ? NS_MATHML_PSEUDO_UNIT_DEPTH : mDepthPseudoUnit;
  UpdateValue(mDepthSign, pseudoUnit, mDepth,
              aDesiredSize, depth);
  depth = std::max(0, depth);

  // update lspace
  if (mLeadingSpacePseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) {
    pseudoUnit = mLeadingSpacePseudoUnit;
    UpdateValue(mLeadingSpaceSign, pseudoUnit, mLeadingSpace,
                aDesiredSize, lspace);
  }

  // update voffset
  if (mVerticalOffsetPseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) {
    pseudoUnit = mVerticalOffsetPseudoUnit;
    UpdateValue(mVerticalOffsetSign, pseudoUnit, mVerticalOffset,
                aDesiredSize, voffset);
  }
  // do the padding now that we have everything
  // The idea here is to maintain the invariant that <mpadded>...</mpadded> (i.e.,
  // with no attributes) looks the same as <mrow>...</mrow>. But when there are
  // attributes, tweak our metrics and move children to achieve the desired visual
  // effects.

  if ((StyleVisibility()->mDirection ?
       mWidthSign : mLeadingSpaceSign) != NS_MATHML_SIGN_INVALID) {
    // there was padding on the left. dismiss the left italic correction now
    // (so that our parent won't correct us)
    mBoundingMetrics.leftBearing = 0;
  }

  if ((StyleVisibility()->mDirection ?
       mLeadingSpaceSign : mWidthSign) != NS_MATHML_SIGN_INVALID) {
    // there was padding on the right. dismiss the right italic correction now
    // (so that our parent won't correct us)
    mBoundingMetrics.width = width;
    mBoundingMetrics.rightBearing = mBoundingMetrics.width;
  }

  nscoord dx = (StyleVisibility()->mDirection ?
                width - initialWidth - lspace : lspace);
    
  aDesiredSize.SetTopAscent(height);
  aDesiredSize.Width() = mBoundingMetrics.width;
  aDesiredSize.Height() = depth + aDesiredSize.TopAscent();
  mBoundingMetrics.ascent = height;
  mBoundingMetrics.descent = depth;
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;

  mReference.x = 0;
  mReference.y = aDesiredSize.TopAscent();

  if (aPlaceOrigin) {
    // Finish reflowing child frames, positioning their origins.
    PositionRowChildFrames(dx, aDesiredSize.TopAscent() - voffset);
  }

  return NS_OK;
}
コード例 #5
0
/* virtual */ nsresult
nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
                                     bool                 aPlaceOrigin,
                                     nsHTMLReflowMetrics& aDesiredSize,
                                     bool                 aWidthOnly)
{
  ///////////////
  // Measure the size of our content using the base class to format like an
  // inferred mrow.
  nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode());
  nsresult rv =
    nsMathMLContainerFrame::Place(aRenderingContext, false, baseSize);

  if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
      DidReflowChildren(GetFirstPrincipalChild());
      return rv;
    }

  nsBoundingMetrics bmBase = baseSize.mBoundingMetrics;
  nscoord dx_left = 0, dx_right = 0;
  nsBoundingMetrics bmLongdivChar, bmRadicalChar;
  nscoord radicalAscent = 0, radicalDescent = 0;
  nscoord longdivAscent = 0, longdivDescent = 0;
  nscoord psi = 0;
  nscoord leading = 0;

  ///////////////
  // Thickness of bars and font metrics
  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);

  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  nsRefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                        fontSizeInflation);
  GetRuleThickness(aRenderingContext, fm, mRuleThickness);
  if (mRuleThickness < onePixel) {
    mRuleThickness = onePixel;
  }

  char16_t one = '1';
  nsBoundingMetrics bmOne =
    nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, aRenderingContext);

  ///////////////
  // General rules: the menclose element takes the size of the enclosed content.
  // We add a padding when needed.

  // determine padding & psi
  nscoord padding = 3 * mRuleThickness;
  nscoord delta = padding % onePixel;
  if (delta)
    padding += onePixel - delta; // round up

  if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
    GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
                         NS_MATHML_DISPLAYSTYLE_BLOCK,
                         mRadicalRuleThickness, leading, psi);

    // make sure that the rule appears on on screen
    if (mRadicalRuleThickness < onePixel) {
      mRadicalRuleThickness = onePixel;
    }

    // adjust clearance psi to get an exact number of pixels -- this
    // gives a nicer & uniform look on stacked radicals (bug 130282)
    delta = psi % onePixel;
    if (delta) {
      psi += onePixel - delta; // round up
    }
  }

  // Set horizontal parameters
  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
      IsToDraw(NOTATION_TOP) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_BOTTOM) ||
      IsToDraw(NOTATION_CIRCLE))
    dx_left = padding;

  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
      IsToDraw(NOTATION_TOP) ||
      IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_BOTTOM) ||
      IsToDraw(NOTATION_CIRCLE))
    dx_right = padding;

  // Set vertical parameters
  if (IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_UPDIAGONALARROW) ||
      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_VERTICALSTRIKE) ||
      IsToDraw(NOTATION_CIRCLE) ||
      IsToDraw(NOTATION_ROUNDEDBOX) ||
      IsToDraw(NOTATION_RADICAL) ||
      IsToDraw(NOTATION_LONGDIV) ||
      IsToDraw(NOTATION_PHASORANGLE)) {
      // set a minimal value for the base height
      bmBase.ascent = std::max(bmOne.ascent, bmBase.ascent);
      bmBase.descent = std::max(0, bmBase.descent);
  }

  mBoundingMetrics.ascent = bmBase.ascent;
  mBoundingMetrics.descent = bmBase.descent;
    
  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
      IsToDraw(NOTATION_TOP) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_CIRCLE))
    mBoundingMetrics.ascent += padding;
  
  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_BOTTOM) ||
      IsToDraw(NOTATION_CIRCLE))
    mBoundingMetrics.descent += padding;

   ///////////////
   // phasorangle notation
  if (IsToDraw(NOTATION_PHASORANGLE)) {
    nscoord phasorangleWidth = kPhasorangleWidth * mRuleThickness;
    // Update horizontal parameters
    dx_left = std::max(dx_left, phasorangleWidth);
  }

  ///////////////
  // updiagonal arrow notation. We need enough space at the top right corner to
  // draw the arrow head.
  if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
    // This is an estimate, see nsDisplayNotation::Paint for the exact head size
    nscoord arrowHeadSize = kArrowHeadSize * mRuleThickness;

    // We want that the arrow shaft strikes the menclose content and that the
    // arrow head does not overlap with that content. Hence we add some space
    // on the right. We don't add space on the top but only ensure that the
    // ascent is large enough.
    dx_right = std::max(dx_right, arrowHeadSize);
    mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, arrowHeadSize);
  }

  ///////////////
  // circle notation: we don't want the ellipse to overlap the enclosed
  // content. Hence, we need to increase the size of the bounding box by a
  // factor of at least sqrt(2).
  if (IsToDraw(NOTATION_CIRCLE)) {
    double ratio = (sqrt(2.0) - 1.0) / 2.0;
    nscoord padding2;

    // Update horizontal parameters
    padding2 = ratio * bmBase.width;

    dx_left = std::max(dx_left, padding2);
    dx_right = std::max(dx_right, padding2);

    // Update vertical parameters
    padding2 = ratio * (bmBase.ascent + bmBase.descent);

    mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
                                     bmBase.ascent + padding2);
    mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
                                      bmBase.descent + padding2);
  }

  ///////////////
  // longdiv notation:
  if (IsToDraw(NOTATION_LONGDIV)) {
    if (aWidthOnly) {
        nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].
          GetMaxWidth(PresContext(), aRenderingContext, fontSizeInflation);

        // Update horizontal parameters
        dx_left = std::max(dx_left, longdiv_width);
    } else {
      // Stretch the parenthesis to the appropriate height if it is not
      // big enough.
      nsBoundingMetrics contSize = bmBase;
      contSize.ascent = mRuleThickness;
      contSize.descent = bmBase.ascent + bmBase.descent + psi;

      // height(longdiv) should be >= height(base) + psi + mRuleThickness
      mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aRenderingContext,
                                             fontSizeInflation,
                                             NS_STRETCH_DIRECTION_VERTICAL,
                                             contSize, bmLongdivChar,
                                             NS_STRETCH_LARGER, false);
      mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar);

      // Update horizontal parameters
      dx_left = std::max(dx_left, bmLongdivChar.width);

      // Update vertical parameters
      longdivAscent = bmBase.ascent + psi + mRuleThickness;
      longdivDescent = std::max(bmBase.descent,
                              (bmLongdivChar.ascent + bmLongdivChar.descent -
                               longdivAscent));

      mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
                                       longdivAscent);
      mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
                                        longdivDescent);
    }
  }

  ///////////////
  // radical notation:
  if (IsToDraw(NOTATION_RADICAL)) {
    nscoord *dx_leading = StyleVisibility()->mDirection ? &dx_right : &dx_left;
    
    if (aWidthOnly) {
      nscoord radical_width = mMathMLChar[mRadicalCharIndex].
        GetMaxWidth(PresContext(), aRenderingContext, fontSizeInflation);
      
      // Update horizontal parameters
      *dx_leading = std::max(*dx_leading, radical_width);
    } else {
      // Stretch the radical symbol to the appropriate height if it is not
      // big enough.
      nsBoundingMetrics contSize = bmBase;
      contSize.ascent = mRadicalRuleThickness;
      contSize.descent = bmBase.ascent + bmBase.descent + psi;

      // height(radical) should be >= height(base) + psi + mRadicalRuleThickness
      mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext,
                                             fontSizeInflation,
                                             NS_STRETCH_DIRECTION_VERTICAL,
                                             contSize, bmRadicalChar,
                                             NS_STRETCH_LARGER,
                                             StyleVisibility()->mDirection);
      mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar);

      // Update horizontal parameters
      *dx_leading = std::max(*dx_leading, bmRadicalChar.width);

      // Update vertical parameters
      radicalAscent = bmBase.ascent + psi + mRadicalRuleThickness;
      radicalDescent = std::max(bmBase.descent,
                              (bmRadicalChar.ascent + bmRadicalChar.descent -
                               radicalAscent));

      mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
                                       radicalAscent);
      mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
                                        radicalDescent);
    }
  }

  ///////////////
  //
  if (IsToDraw(NOTATION_CIRCLE) ||
      IsToDraw(NOTATION_ROUNDEDBOX) ||
      (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) {
    // center the menclose around the content (horizontally)
    dx_left = dx_right = std::max(dx_left, dx_right);
  }

  ///////////////
  // The maximum size is now computed: set the remaining parameters
  mBoundingMetrics.width = dx_left + bmBase.width + dx_right;

  mBoundingMetrics.leftBearing = std::min(0, dx_left + bmBase.leftBearing);
  mBoundingMetrics.rightBearing =
    std::max(mBoundingMetrics.width, dx_left + bmBase.rightBearing);
  
  aDesiredSize.Width() = mBoundingMetrics.width;

  aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent,
                                            baseSize.BlockStartAscent()));
  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
    std::max(mBoundingMetrics.descent,
             baseSize.Height() - baseSize.BlockStartAscent());

  if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
    nscoord desiredSizeAscent = aDesiredSize.BlockStartAscent();
    nscoord desiredSizeDescent = aDesiredSize.Height() -
                                 aDesiredSize.BlockStartAscent();
    
    if (IsToDraw(NOTATION_LONGDIV)) {
      desiredSizeAscent = std::max(desiredSizeAscent,
                                 longdivAscent + leading);
      desiredSizeDescent = std::max(desiredSizeDescent,
                                  longdivDescent + mRuleThickness);
    }
    
    if (IsToDraw(NOTATION_RADICAL)) {
      desiredSizeAscent = std::max(desiredSizeAscent,
                                 radicalAscent + leading);
      desiredSizeDescent = std::max(desiredSizeDescent,
                                    radicalDescent + mRadicalRuleThickness);
    }

    aDesiredSize.SetBlockStartAscent(desiredSizeAscent);
    aDesiredSize.Height() = desiredSizeAscent + desiredSizeDescent;
  }
    
  if (IsToDraw(NOTATION_CIRCLE) ||
      IsToDraw(NOTATION_ROUNDEDBOX) ||
      (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) {
    // center the menclose around the content (vertically)
    nscoord dy = std::max(aDesiredSize.BlockStartAscent() - bmBase.ascent,
                          aDesiredSize.Height() -
                          aDesiredSize.BlockStartAscent() - bmBase.descent);

    aDesiredSize.SetBlockStartAscent(bmBase.ascent + dy);
    aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + bmBase.descent + dy;
  }

  // Update mBoundingMetrics ascent/descent
  if (IsToDraw(NOTATION_TOP) ||
      IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_UPDIAGONALARROW) ||
      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_VERTICALSTRIKE) ||
      IsToDraw(NOTATION_CIRCLE) ||
      IsToDraw(NOTATION_ROUNDEDBOX))
    mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
  
  if (IsToDraw(NOTATION_BOTTOM) ||
      IsToDraw(NOTATION_RIGHT) ||
      IsToDraw(NOTATION_LEFT) ||
      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_UPDIAGONALARROW) ||
      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
      IsToDraw(NOTATION_VERTICALSTRIKE) ||
      IsToDraw(NOTATION_CIRCLE) ||
      IsToDraw(NOTATION_ROUNDEDBOX))
    mBoundingMetrics.descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent();

  // phasorangle notation:
  // move up from the bottom by the angled line height
  if (IsToDraw(NOTATION_PHASORANGLE))
    mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, 2 * kPhasorangleWidth * mRuleThickness - mBoundingMetrics.descent);
  
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  
  mReference.x = 0;
  mReference.y = aDesiredSize.BlockStartAscent();

  if (aPlaceOrigin) {
    //////////////////
    // Set position and size of MathMLChars
    if (IsToDraw(NOTATION_LONGDIV))
      mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left -
                                                    bmLongdivChar.width,
                                                    aDesiredSize.BlockStartAscent() -
                                                    longdivAscent,
                                                    bmLongdivChar.width,
                                                    bmLongdivChar.ascent +
                                                    bmLongdivChar.descent));

    if (IsToDraw(NOTATION_RADICAL)) {
      nscoord dx = (StyleVisibility()->mDirection ?
                    dx_left + bmBase.width : dx_left - bmRadicalChar.width);

      mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx,
                                                    aDesiredSize.BlockStartAscent() -
                                                    radicalAscent,
                                                    bmRadicalChar.width,
                                                    bmRadicalChar.ascent +
                                                    bmRadicalChar.descent));
    }

    mContentWidth = bmBase.width;

    //////////////////
    // Finish reflowing child frames
    PositionRowChildFrames(dx_left, aDesiredSize.BlockStartAscent());
  }

  return NS_OK;
}
コード例 #6
0
void
nsMathMLmtableOuterFrame::Reflow(nsPresContext*          aPresContext,
                                 nsHTMLReflowMetrics&     aDesiredSize,
                                 const nsHTMLReflowState& aReflowState,
                                 nsReflowStatus&          aStatus)
{
  nsAutoString value;
  // we want to return a table that is anchored according to the align attribute

  nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
  NS_ASSERTION(aDesiredSize.Height() >= 0, "illegal height for mtable");
  NS_ASSERTION(aDesiredSize.Width() >= 0, "illegal width for mtable");

  // see if the user has set the align attribute on the <mtable>
  int32_t rowIndex = 0;
  eAlign tableAlign = eAlign_axis;
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, value);
  if (!value.IsEmpty()) {
    ParseAlignAttribute(value, tableAlign, rowIndex);
  }

  // adjustments if there is a specified row from where to anchor the table
  // (conceptually: when there is no row of reference, picture the table as if
  // it is wrapped in a single big fictional row at dy = 0, this way of
  // doing so allows us to have a single code path for all cases).
  nscoord dy = 0;
  WritingMode wm = aDesiredSize.GetWritingMode();
  nscoord blockSize = aDesiredSize.BSize(wm);
  nsIFrame* rowFrame = nullptr;
  if (rowIndex) {
    rowFrame = GetRowFrameAt(rowIndex);
    if (rowFrame) {
      // translate the coordinates to be relative to us and in our writing mode
      nsIFrame* frame = rowFrame;
      LogicalRect rect(wm, frame->GetRect(),
                       aReflowState.ComputedSizeAsContainerIfConstrained());
      blockSize = rect.BSize(wm);
      do {
        dy += rect.BStart(wm);
        frame = frame->GetParent();
      } while (frame != this);
    }
  }
  switch (tableAlign) {
    case eAlign_top:
      aDesiredSize.SetBlockStartAscent(dy);
      break;
    case eAlign_bottom:
      aDesiredSize.SetBlockStartAscent(dy + blockSize);
      break;
    case eAlign_center:
      aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
      break;
    case eAlign_baseline:
      if (rowFrame) {
        // anchor the table on the baseline of the row of reference
        nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
        if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
          aDesiredSize.SetBlockStartAscent(dy + rowAscent);
          break;
        }
      }
      // in other situations, fallback to center
      aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
      break;
    case eAlign_axis:
    default: {
      // XXX should instead use style data from the row of reference here ?
      RefPtr<nsFontMetrics> fm;
      nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                            nsLayoutUtils::
                                            FontSizeInflationFor(this));
      nscoord axisHeight;
      GetAxisHeight(aReflowState.rendContext->GetDrawTarget(), fm, axisHeight);
      if (rowFrame) {
        // anchor the table on the axis of the row of reference
        // XXX fallback to baseline because it is a hard problem
        // XXX need to fetch the axis of the row; would need rowalign=axis to work better
        nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
        if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
          aDesiredSize.SetBlockStartAscent(dy + rowAscent);
          break;
        }
      }
      // in other situations, fallback to using half of the height
      aDesiredSize.SetBlockStartAscent(dy + blockSize / 2 + axisHeight);
    }
  }

  mReference.x = 0;
  mReference.y = aDesiredSize.BlockStartAscent();

  // just make-up a bounding metrics
  mBoundingMetrics = nsBoundingMetrics();
  mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
  mBoundingMetrics.descent = aDesiredSize.Height() -
                             aDesiredSize.BlockStartAscent();
  mBoundingMetrics.width = aDesiredSize.Width();
  mBoundingMetrics.leftBearing = 0;
  mBoundingMetrics.rightBearing = aDesiredSize.Width();

  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
コード例 #7
0
void
nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
                                               nsHTMLReflowMetrics& aButtonDesiredSize,
                                               const nsHTMLReflowState& aButtonReflowState,
                                               nsIFrame* aFirstKid)
{
  // Buttons have some bonus renderer-determined border/padding,
  // which occupies part of the button's content-box area:
  const nsMargin focusPadding = mRenderer.GetAddedButtonBorderAndPadding();

  nsSize availSize(aButtonReflowState.ComputedWidth(), NS_INTRINSICSIZE);

  // Indent the child inside us by the focus border. We must do this separate
  // from the regular border.
  availSize.width -= focusPadding.LeftRight();
  
  // See whether out availSize's width is big enough.  If it's smaller than our
  // intrinsic min width, that means that the kid wouldn't really fit; for a
  // better look in such cases we adjust the available width and our left
  // offset to allow the kid to spill left into our padding.
  nscoord xoffset = focusPadding.left +
    aButtonReflowState.ComputedPhysicalBorderPadding().left;
  nscoord extrawidth = GetMinWidth(aButtonReflowState.rendContext) -
    aButtonReflowState.ComputedWidth();
  if (extrawidth > 0) {
    nscoord extraleft = extrawidth / 2;
    nscoord extraright = extrawidth - extraleft;
    NS_ASSERTION(extraright >=0, "How'd that happen?");
    
    // Do not allow the extras to be bigger than the relevant padding
    extraleft = std::min(extraleft, aButtonReflowState.ComputedPhysicalPadding().left);
    extraright = std::min(extraright, aButtonReflowState.ComputedPhysicalPadding().right);
    xoffset -= extraleft;
    availSize.width += extraleft + extraright;
  }
  availSize.width = std::max(availSize.width,0);
  
  // Give child a clone of the button's reflow state, with height/width reduced
  // by focusPadding, so that descendants with height:100% don't protrude.
  nsHTMLReflowState adjustedButtonReflowState =
    CloneReflowStateWithReducedContentBox(aButtonReflowState, focusPadding);

  nsHTMLReflowState contentsReflowState(aPresContext,
                                        adjustedButtonReflowState,
                                        aFirstKid, availSize);

  nsReflowStatus contentsReflowStatus;
  nsHTMLReflowMetrics contentsDesiredSize(aButtonReflowState.GetWritingMode());
  ReflowChild(aFirstKid, aPresContext,
              contentsDesiredSize, contentsReflowState,
              xoffset,
              focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top,
              0, contentsReflowStatus);
  MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
             "We gave button-contents frame unconstrained available height, "
             "so it should be complete");

  // Compute the button's content-box height:
  nscoord buttonContentBoxHeight = 0;
  if (aButtonReflowState.ComputedHeight() != NS_INTRINSICSIZE) {
    // Button has a fixed height -- that's its content-box height.
    buttonContentBoxHeight = aButtonReflowState.ComputedHeight();
  } else {
    // Button is intrinsically sized -- it should shrinkwrap the
    // button-contents' height, plus any focus-padding space:
    buttonContentBoxHeight =
      contentsDesiredSize.Height() + focusPadding.TopBottom();

    // Make sure we obey min/max-height in the case when we're doing intrinsic
    // sizing (we get it for free when we have a non-intrinsic
    // aButtonReflowState.ComputedHeight()).  Note that we do this before
    // adjusting for borderpadding, since mComputedMaxHeight and
    // mComputedMinHeight are content heights.
    buttonContentBoxHeight =
      NS_CSS_MINMAX(buttonContentBoxHeight,
                    aButtonReflowState.ComputedMinHeight(),
                    aButtonReflowState.ComputedMaxHeight());
  }

  // Center child vertically in the button
  // (technically, inside of the button's focus-padding area)
  nscoord extraSpace =
    buttonContentBoxHeight - focusPadding.TopBottom() -
    contentsDesiredSize.Height();

  nscoord yoffset = std::max(0, extraSpace / 2);

  // Adjust yoffset to be in terms of the button's frame-rect, instead of
  // its focus-padding rect:
  yoffset += focusPadding.top + aButtonReflowState.ComputedPhysicalBorderPadding().top;

  // Place the child
  FinishReflowChild(aFirstKid, aPresContext,
                    &contentsReflowState, contentsDesiredSize,
                    xoffset, yoffset, 0);

  // Make sure we have a useful 'ascent' value for the child
  if (contentsDesiredSize.TopAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
    contentsDesiredSize.SetTopAscent(aFirstKid->GetBaseline());
  }

  // OK, we're done with the child frame.
  // Use what we learned to populate the button frame's reflow metrics.
  //  * Button's height & width are content-box size + border-box contribution:
  aButtonDesiredSize.Width() = aButtonReflowState.ComputedWidth() +
    aButtonReflowState.ComputedPhysicalBorderPadding().LeftRight();

  aButtonDesiredSize.Height() = buttonContentBoxHeight +
    aButtonReflowState.ComputedPhysicalBorderPadding().TopBottom();

  //  * Button's ascent is its child's ascent, plus the child's y-offset
  // within our frame:
  aButtonDesiredSize.SetTopAscent(contentsDesiredSize.TopAscent() + yoffset);

  aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
}
コード例 #8
0
void
nsVideoFrame::Reflow(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aMetrics,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsVideoFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                  ("enter nsVideoFrame::Reflow: availSize=%d,%d",
                  aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));

  NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");

  aStatus = NS_FRAME_COMPLETE;

  aMetrics.Width() = aReflowState.ComputedWidth();
  aMetrics.Height() = aReflowState.ComputedHeight();

  // stash this away so we can compute our inner area later
  mBorderPadding   = aReflowState.ComputedPhysicalBorderPadding();

  aMetrics.Width() += mBorderPadding.left + mBorderPadding.right;
  aMetrics.Height() += mBorderPadding.top + mBorderPadding.bottom;

  // Reflow the child frames. We may have up to two, an image frame
  // which is the poster, and a box frame, which is the video controls.
  for (nsIFrame *child = mFrames.FirstChild();
       child;
       child = child->GetNextSibling()) {
    if (child->GetContent() == mPosterImage) {
      // Reflow the poster frame.
      nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child);
      nsHTMLReflowMetrics kidDesiredSize(aReflowState);
      WritingMode wm = imageFrame->GetWritingMode();
      LogicalSize availableSize = aReflowState.AvailableSize(wm);
      nsHTMLReflowState kidReflowState(aPresContext,
                                       aReflowState,
                                       imageFrame,
                                       availableSize,
                                       aMetrics.Width(),
                                       aMetrics.Height());

      nsRect posterRenderRect;
      if (ShouldDisplayPoster()) {
        posterRenderRect =
          nsRect(nsPoint(mBorderPadding.left, mBorderPadding.top),
                 nsSize(aReflowState.ComputedWidth(),
                        aReflowState.ComputedHeight()));
      }
      kidReflowState.SetComputedWidth(posterRenderRect.width);
      kidReflowState.SetComputedHeight(posterRenderRect.height);
      ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState,
                  posterRenderRect.x, posterRenderRect.y, 0, aStatus);
      FinishReflowChild(imageFrame, aPresContext,
                        kidDesiredSize, &kidReflowState,
                        posterRenderRect.x, posterRenderRect.y, 0);
    } else if (child->GetContent() == mVideoControls) {
      // Reflow the video controls frame.
      nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext);
      nsSize size = child->GetSize();
      nsBoxFrame::LayoutChildAt(boxState,
                                child,
                                nsRect(mBorderPadding.left,
                                       mBorderPadding.top,
                                       aReflowState.ComputedWidth(),
                                       aReflowState.ComputedHeight()));
      if (child->GetSize() != size) {
        nsRefPtr<nsRunnable> event = new DispatchResizeToControls(child->GetContent());
        nsContentUtils::AddScriptRunner(event);
      }
    } else if (child->GetContent() == mCaptionDiv) {
      // Reflow to caption div
      nsHTMLReflowMetrics kidDesiredSize(aReflowState);
      WritingMode wm = child->GetWritingMode();
      LogicalSize availableSize = aReflowState.AvailableSize(wm);
      nsHTMLReflowState kidReflowState(aPresContext,
                                       aReflowState,
                                       child,
                                       availableSize,
                                       aMetrics.Width(),
                                       aMetrics.Height());
      nsSize size(aReflowState.ComputedWidth(), aReflowState.ComputedHeight());
      size.width -= kidReflowState.ComputedPhysicalBorderPadding().LeftRight();
      size.height -= kidReflowState.ComputedPhysicalBorderPadding().TopBottom();

      kidReflowState.SetComputedWidth(std::max(size.width, 0));
      kidReflowState.SetComputedHeight(std::max(size.height, 0));

      ReflowChild(child, aPresContext, kidDesiredSize, kidReflowState,
                  mBorderPadding.left, mBorderPadding.top, 0, aStatus);
      FinishReflowChild(child, aPresContext,
                        kidDesiredSize, &kidReflowState,
                        mBorderPadding.left, mBorderPadding.top, 0);
    }
  }
  aMetrics.SetOverflowAreasToDesiredBounds();

  FinishAndStoreOverflow(&aMetrics);

  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                  ("exit nsVideoFrame::Reflow: size=%d,%d",
                  aMetrics.Width(), aMetrics.Height()));
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
}
コード例 #9
0
ファイル: nsMathMLmoFrame.cpp プロジェクト: Jar-win/Waterfox
// NOTE: aDesiredStretchSize is an IN/OUT parameter
//       On input  - it contains our current size
//       On output - the same size or the new size that we want
NS_IMETHODIMP
nsMathMLmoFrame::Stretch(nsRenderingContext& aRenderingContext,
                         nsStretchDirection   aStretchDirection,
                         nsBoundingMetrics&   aContainerSize,
                         nsHTMLReflowMetrics& aDesiredStretchSize)
{
  if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
    NS_WARNING("it is wrong to fire stretch more than once on a frame");
    return NS_OK;
  }
  mPresentationData.flags |= NS_MATHML_STRETCH_DONE;

  nsIFrame* firstChild = mFrames.FirstChild();

  // get the axis height;
  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  nsRefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                        fontSizeInflation);
  nscoord axisHeight, height;
  GetAxisHeight(aRenderingContext, fm, axisHeight);

  // get the leading to be left at the top and the bottom of the stretched char
  // this seems more reliable than using fm->GetLeading() on suspicious fonts
  nscoord em;
  GetEmHeight(fm, em);
  nscoord leading = NSToCoordRound(0.2f * em);

  // Operators that are stretchy, or those that are to be centered
  // to cater for fonts that are not math-aware, are handled by the MathMLChar
  // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time)
  bool useMathMLChar = UseMathMLChar();

  nsBoundingMetrics charSize;
  nsBoundingMetrics container = aDesiredStretchSize.mBoundingMetrics;
  bool isVertical = false;

  if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) ||
       (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT))  &&
      (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL)) {
    isVertical = true;
  }

  uint32_t stretchHint =
    GetStretchHint(mFlags, mPresentationData, isVertical, StyleFont());

  if (useMathMLChar) {
    nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics;

    if (stretchHint != NS_STRETCH_NONE) {

      container = aContainerSize;

      // some adjustments if the operator is symmetric and vertical

      if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
        // we need to center about the axis
        nscoord delta = std::max(container.ascent - axisHeight,
                               container.descent + axisHeight);
        container.ascent = delta + axisHeight;
        container.descent = delta - axisHeight;

        // get ready in case we encounter user-desired min-max size
        delta = std::max(initialSize.ascent - axisHeight,
                       initialSize.descent + axisHeight);
        initialSize.ascent = delta + axisHeight;
        initialSize.descent = delta - axisHeight;
      }

      // check for user-desired min-max size

      if (mMaxSize != NS_MATHML_OPERATOR_SIZE_INFINITY && mMaxSize > 0.0f) {
        // if we are here, there is a user defined maxsize ...
        //XXX Set stretchHint = NS_STRETCH_NORMAL? to honor the maxsize as close as possible?
        if (NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)) {
          // there is an explicit value like maxsize="20pt"
          // try to maintain the aspect ratio of the char
          float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent);
          container.ascent =
            std::min(container.ascent, nscoord(initialSize.ascent * aspect));
          container.descent =
            std::min(container.descent, nscoord(initialSize.descent * aspect));
          // below we use a type cast instead of a conversion to avoid a VC++ bug
          // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP
          container.width =
            std::min(container.width, (nscoord)mMaxSize);
        }
        else { // multiplicative value
          container.ascent =
            std::min(container.ascent, nscoord(initialSize.ascent * mMaxSize));
          container.descent =
            std::min(container.descent, nscoord(initialSize.descent * mMaxSize));
          container.width =
            std::min(container.width, nscoord(initialSize.width * mMaxSize));
        }

        if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
          // re-adjust to align the char with the bottom of the initial container
          height = container.ascent + container.descent;
          container.descent = aContainerSize.descent;
          container.ascent = height - container.descent;
        }
      }

      if (mMinSize > 0.0f) {
        // if we are here, there is a user defined minsize ...
        // always allow the char to stretch in its natural direction,
        // even if it is different from the caller's direction 
        if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT &&
            aStretchDirection != mEmbellishData.direction) {
          aStretchDirection = NS_STRETCH_DIRECTION_DEFAULT;
          // but when we are not honoring the requested direction
          // we should not use the caller's container size either
          container = initialSize;
        }
        if (NS_MATHML_OPERATOR_MINSIZE_IS_ABSOLUTE(mFlags)) {
          // there is an explicit value like minsize="20pt"
          // try to maintain the aspect ratio of the char
          float aspect = mMinSize / float(initialSize.ascent + initialSize.descent);
          container.ascent =
            std::max(container.ascent, nscoord(initialSize.ascent * aspect));
          container.descent =
            std::max(container.descent, nscoord(initialSize.descent * aspect));
          container.width =
            std::max(container.width, (nscoord)mMinSize);
        }
        else { // multiplicative value
          container.ascent =
            std::max(container.ascent, nscoord(initialSize.ascent * mMinSize));
          container.descent =
            std::max(container.descent, nscoord(initialSize.descent * mMinSize));
          container.width =
            std::max(container.width, nscoord(initialSize.width * mMinSize));
        }

        if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
          // re-adjust to align the char with the bottom of the initial container
          height = container.ascent + container.descent;
          container.descent = aContainerSize.descent;
          container.ascent = height - container.descent;
        }
      }
    }

    // let the MathMLChar stretch itself...
    nsresult res = mMathMLChar.Stretch(PresContext(), aRenderingContext,
                                       fontSizeInflation,
                                       aStretchDirection, container, charSize,
                                       stretchHint,
                                       StyleVisibility()->mDirection);
    if (NS_FAILED(res)) {
      // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed)
      // clear our 'form' to behave as if the operator wasn't in the dictionary
      mFlags &= ~NS_MATHML_OPERATOR_FORM;
      useMathMLChar = false;
    }
  }

  // Place our children using the default method
  // This will allow our child text frame to get its DidReflow()
  nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize);
  if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
    // Make sure the child frames get their DidReflow() calls.
    DidReflowChildren(mFrames.FirstChild());
  }

  if (useMathMLChar) {
    // update our bounding metrics... it becomes that of our MathML char
    mBoundingMetrics = charSize;

    // if the returned direction is 'unsupported', the char didn't actually change. 
    // So we do the centering only if necessary
    if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED ||
        NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {

      bool largeopOnly =
        (NS_STRETCH_LARGEOP & stretchHint) != 0 &&
        (NS_STRETCH_VARIABLE_MASK & stretchHint) == 0;

      if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
        // the desired size returned by mMathMLChar maybe different
        // from the size of the container.
        // the mMathMLChar.mRect.y calculation is subtle, watch out!!!

        height = mBoundingMetrics.ascent + mBoundingMetrics.descent;
        if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) ||
            NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
          // For symmetric and vertical operators, or for operators that are always
          // centered ('+', '*', etc) we want to center about the axis of the container
          mBoundingMetrics.descent = height/2 - axisHeight;
        } else if (!largeopOnly) {
          // Align the center of the char with the center of the container
          mBoundingMetrics.descent = height/2 +
            (container.ascent + container.descent)/2 - container.ascent;
        } // else align the baselines
        mBoundingMetrics.ascent = height - mBoundingMetrics.descent;
      }
    }
  }

  // Fixup for the final height.
  // On one hand, our stretchy height can sometimes be shorter than surrounding
  // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading|
  // that is smaller than the ASCII's ascent, hence when painting the background
  // later, it won't look uniform along the line.
  // On the other hand, sometimes we may leave too much gap when our glyph happens
  // to come from a font with tall glyphs. For example, since CMEX10 has very tall
  // glyphs, its natural font metrics are large, even if we pick a small glyph
  // whose size is comparable to the size of a normal ASCII glyph.
  // So to avoid uneven spacing in either of these two cases, we use the height
  // of the ASCII font as a reference and try to match it if possible.

  // special case for accents... keep them short to improve mouse operations...
  // an accent can only be the non-first child of <mover>, <munder>, <munderover>
  bool isAccent =
    NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags);
  if (isAccent) {
    nsEmbellishData parentData;
    GetEmbellishDataFrom(GetParent(), parentData);
    isAccent =
       (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) ||
        NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) &&
       parentData.coreFrame != this;
  }
  if (isAccent && firstChild) {
    // see bug 188467 for what is going on here
    nscoord dy = aDesiredStretchSize.BlockStartAscent() -
      (mBoundingMetrics.ascent + leading);
    aDesiredStretchSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
    aDesiredStretchSize.Height() = aDesiredStretchSize.BlockStartAscent() +
                                   mBoundingMetrics.descent;

    firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy));
  }
  else if (useMathMLChar) {
    nscoord ascent = fm->MaxAscent();
    nscoord descent = fm->MaxDescent();
    aDesiredStretchSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent + leading, ascent));
    aDesiredStretchSize.Height() = aDesiredStretchSize.BlockStartAscent() +
                                 std::max(mBoundingMetrics.descent + leading, descent);
  }
  aDesiredStretchSize.Width() = mBoundingMetrics.width;
  aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics;
  mReference.x = 0;
  mReference.y = aDesiredStretchSize.BlockStartAscent();
  // Place our mMathMLChar, its origin is in our coordinate system
  if (useMathMLChar) {
    nscoord dy = aDesiredStretchSize.BlockStartAscent() - mBoundingMetrics.ascent;
    mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent));
  }

  // Before we leave... there is a last item in the check-list:
  // If our parent is not embellished, it means we are the outermost embellished
  // container and so we put the spacing, otherwise we don't include the spacing,
  // the outermost embellished container will take care of it.

  if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {

    // Account the spacing if we are not an accent with explicit attributes
    nscoord leadingSpace = mEmbellishData.leadingSpace;
    if (isAccent && !NS_MATHML_OPERATOR_HAS_LSPACE_ATTR(mFlags)) {
      leadingSpace = 0;
    }
    nscoord trailingSpace = mEmbellishData.trailingSpace;
    if (isAccent && !NS_MATHML_OPERATOR_HAS_RSPACE_ATTR(mFlags)) {
      trailingSpace = 0;
    }

    mBoundingMetrics.width += leadingSpace + trailingSpace;
    aDesiredStretchSize.Width() = mBoundingMetrics.width;
    aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;

    nscoord dx = (StyleVisibility()->mDirection ?
                  trailingSpace : leadingSpace);
    if (dx) {
      // adjust the offsets
      mBoundingMetrics.leftBearing += dx;
      mBoundingMetrics.rightBearing += dx;
      aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
      aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;

      if (useMathMLChar) {
        nsRect rect;
        mMathMLChar.GetRect(rect);
        mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y,
                                   rect.width, rect.height));
      }
      else {
        nsIFrame* childFrame = firstChild;
        while (childFrame) {
          childFrame->SetPosition(childFrame->GetPosition() +
                                  nsPoint(dx, 0));
          childFrame = childFrame->GetNextSibling();
        }
      }
    }
  }

  // Finished with these:
  ClearSavedChildMetrics();
  // Set our overflow area
  GatherAndStoreOverflow(&aDesiredStretchSize);

  // There used to be code here to change the height of the child frame to
  // change the caret height, but the text frame that manages the caret is now
  // not a direct child but wrapped in a block frame.  See also bug 412033.

  return NS_OK;
}
コード例 #10
0
/* virtual */ nsresult
nsMathMLmunderoverFrame::Place(nsRenderingContext& aRenderingContext,
                               bool                 aPlaceOrigin,
                               nsHTMLReflowMetrics& aDesiredSize)
{
  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
      StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
    //place like sub sup or subsup
    if (mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
      return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                          aRenderingContext,
                                                          aPlaceOrigin,
                                                          aDesiredSize,
                                                          this, 0, 0,
                                                          fontSizeInflation);
    } else if (mContent->IsMathMLElement( nsGkAtoms::munder_)) {
      return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                          aRenderingContext,
                                                          aPlaceOrigin,
                                                          aDesiredSize,
                                                          this, 0, 0,
                                                          fontSizeInflation);
    } else {
      NS_ASSERTION(mContent->IsMathMLElement(nsGkAtoms::mover_),
                   "mContent->NodeInfo()->NameAtom() not recognized");
      return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                          aRenderingContext,
                                                          aPlaceOrigin,
                                                          aDesiredSize,
                                                          this, 0, 0,
                                                          fontSizeInflation);
    }
    
  }

  ////////////////////////////////////
  // Get the children's desired sizes

  nsBoundingMetrics bmBase, bmUnder, bmOver;
  nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode());
  nsHTMLReflowMetrics underSize(aDesiredSize.GetWritingMode());
  nsHTMLReflowMetrics overSize(aDesiredSize.GetWritingMode());
  nsIFrame* overFrame = nullptr;
  nsIFrame* underFrame = nullptr;
  nsIFrame* baseFrame = mFrames.FirstChild();
  underSize.SetBlockStartAscent(0);
  overSize.SetBlockStartAscent(0);
  bool haveError = false;
  if (baseFrame) {
    if (mContent->IsAnyOfMathMLElements(nsGkAtoms::munder_,
                                        nsGkAtoms::munderover_)) {
      underFrame = baseFrame->GetNextSibling();
    } else if (mContent->IsMathMLElement(nsGkAtoms::mover_)) {
      overFrame = baseFrame->GetNextSibling();
    }
  }
  if (underFrame && mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
    overFrame = underFrame->GetNextSibling();
  }
  
  if (mContent->IsMathMLElement(nsGkAtoms::munder_)) {
    if (!baseFrame || !underFrame || underFrame->GetNextSibling()) {
      // report an error, encourage people to get their markups in order
      haveError = true;
    }
  }
  if (mContent->IsMathMLElement(nsGkAtoms::mover_)) {
    if (!baseFrame || !overFrame || overFrame->GetNextSibling()) {
      // report an error, encourage people to get their markups in order
      haveError = true;
    }
  }
  if (mContent->IsMathMLElement(nsGkAtoms::munderover_)) {
    if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) {
      // report an error, encourage people to get their markups in order
      haveError = true;
    }
  }
  if (haveError) {
    if (aPlaceOrigin) {
      ReportChildCountError();
    } 
    return ReflowError(aRenderingContext, aDesiredSize);
  }
  GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
  if (underFrame) {
    GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
  }
  if (overFrame) {
    GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
  }

  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);

  ////////////////////
  // Place Children

  nsRefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                        fontSizeInflation);

  nscoord xHeight = fm->XHeight();
  nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();

  nscoord ruleThickness;
  GetRuleThickness (aRenderingContext, fm, ruleThickness);

  nscoord correction = 0;
  GetItalicCorrection (bmBase, correction);

  // there are 2 different types of placement depending on 
  // whether we want an accented under or not

  nscoord underDelta1 = 0; // gap between base and underscript
  nscoord underDelta2 = 0; // extra space beneath underscript

  if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
    // Rule 13a, App. G, TeXbook
    nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; 
    GetBigOpSpacings (fm, 
                      dummy, bigOpSpacing2, 
                      dummy, bigOpSpacing4, 
                      bigOpSpacing5);
    if (mathFont) {
      // XXXfredw The Open Type MATH table has some StretchStack* parameters
      // that we may use when the base is a stretchy horizontal operator. See
      // bug 963131.
      bigOpSpacing2 =
        mathFont->GetMathConstant(gfxFontEntry::LowerLimitGapMin,
                                  oneDevPixel);
      bigOpSpacing4 =
        mathFont->GetMathConstant(gfxFontEntry::LowerLimitBaselineDropMin,
                                  oneDevPixel);
      bigOpSpacing5 = 0;
    }
    underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
    underDelta2 = bigOpSpacing5;
  }
  else {
    // No corresponding rule in TeXbook - we are on our own here
    // XXX tune the gap delta between base and underscript 
    // XXX Should we use Rule 10 like \underline does?
    // XXXfredw Perhaps use the Underbar* parameters of the MATH table. See
    // bug 963125.
    underDelta1 = ruleThickness + onePixel/2;
    underDelta2 = ruleThickness;
  }
  // empty under?
  if (!(bmUnder.ascent + bmUnder.descent)) {
    underDelta1 = 0;
    underDelta2 = 0;
  }

  nscoord overDelta1 = 0; // gap between base and overscript
  nscoord overDelta2 = 0; // extra space above overscript

  if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {    
    // Rule 13a, App. G, TeXbook
    // XXXfredw The Open Type MATH table has some StretchStack* parameters
    // that we may use when the base is a stretchy horizontal operator. See
    // bug 963131.
    nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; 
    GetBigOpSpacings (fm, 
                      bigOpSpacing1, dummy, 
                      bigOpSpacing3, dummy, 
                      bigOpSpacing5);
    if (mathFont) {
      // XXXfredw The Open Type MATH table has some StretchStack* parameters
      // that we may use when the base is a stretchy horizontal operator. See
      // bug 963131.
      bigOpSpacing1 =
        mathFont->GetMathConstant(gfxFontEntry::UpperLimitGapMin,
                                  oneDevPixel);
      bigOpSpacing3 =
        mathFont->GetMathConstant(gfxFontEntry::UpperLimitBaselineRiseMin,
                                  oneDevPixel);
      bigOpSpacing5 = 0;
    }
    overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
    overDelta2 = bigOpSpacing5;

    // XXX This is not a TeX rule... 
    // delta1 (as computed abvove) can become really big when bmOver.descent is
    // negative,  e.g., if the content is &OverBar. In such case, we use the height
    if (bmOver.descent < 0)    
      overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
  }
  else {
    // Rule 12, App. G, TeXbook
    // We are going to modify this rule to make it more general.
    // The idea behind Rule 12 in the TeXBook is to keep the accent
    // as close to the base as possible, while ensuring that the
    // distance between the *baseline* of the accent char and 
    // the *baseline* of the base is atleast x-height. 
    // The idea is that for normal use, we would like all the accents
    // on a line to line up atleast x-height above the baseline 
    // if possible. 
    // When the ascent of the base is >= x-height, 
    // the baseline of the accent char is placed just above the base
    // (specifically, the baseline of the accent char is placed 
    // above the baseline of the base by the ascent of the base).
    // For ease of implementation, 
    // this assumes that the font-designer designs accents 
    // in such a way that the bottom of the accent is atleast x-height
    // above its baseline, otherwise there will be collisions
    // with the base. Also there should be proper padding between
    // the bottom of the accent char and its baseline.
    // The above rule may not be obvious from a first
    // reading of rule 12 in the TeXBook !!!
    // The mathml <mover> tag can use accent chars that
    // do not follow this convention. So we modify TeX's rule 
    // so that TeX's rule gets subsumed for accents that follow 
    // TeX's convention,
    // while also allowing accents that do not follow the convention :
    // we try to keep the *bottom* of the accent char atleast x-height 
    // from the baseline of the base char. we also slap on an extra
    // padding between the accent and base chars.
    overDelta1 = ruleThickness + onePixel/2;
    nscoord accentBaseHeight = xHeight;
    if (mathFont) {
      accentBaseHeight =
        mathFont->GetMathConstant(gfxFontEntry::AccentBaseHeight,
                                  oneDevPixel);
    }
    if (bmBase.ascent < accentBaseHeight) {
      // also ensure at least accentBaseHeight above the baseline of the base
      overDelta1 += accentBaseHeight - bmBase.ascent;
    }
    overDelta2 = ruleThickness;
  }
  // empty over?
  if (!(bmOver.ascent + bmOver.descent)) {
    overDelta1 = 0;
    overDelta2 = 0;
  }

  nscoord dxBase = 0, dxOver = 0, dxUnder = 0;
  nsAutoString valueAlign;
  enum {
    center,
    left,
    right
  } alignPosition = center;

  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, valueAlign)) {
    if (valueAlign.EqualsLiteral("left")) {
      alignPosition = left;
    } else if (valueAlign.EqualsLiteral("right")) {
      alignPosition = right;
    }
  }

  //////////
  // pass 1, do what <mover> does: attach the overscript on the base

  // Ad-hoc - This is to override fonts which have ready-made _accent_
  // glyphs with negative lbearing and rbearing. We want to position
  // the overscript ourselves
  nscoord overWidth = bmOver.width;
  if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) {
    overWidth = bmOver.rightBearing - bmOver.leftBearing;
    dxOver = -bmOver.leftBearing;
  }

  if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
    mBoundingMetrics.width = bmBase.width; 
    if (alignPosition == center) {
      dxOver += correction;
    }
  }
  else {
    mBoundingMetrics.width = std::max(bmBase.width, overWidth);
    if (alignPosition == center) {
      dxOver += correction/2;
    }
  }
  
  if (alignPosition == center) {
    dxOver += (mBoundingMetrics.width - overWidth)/2;
    dxBase = (mBoundingMetrics.width - bmBase.width)/2;
  } else if (alignPosition == right) {
    dxOver += mBoundingMetrics.width - overWidth;
    dxBase = mBoundingMetrics.width - bmBase.width;
  }

  mBoundingMetrics.ascent = 
    bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent;
  mBoundingMetrics.descent = bmBase.descent;
  mBoundingMetrics.leftBearing = 
    std::min(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
  mBoundingMetrics.rightBearing = 
    std::max(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);

  //////////
  // pass 2, do what <munder> does: attach the underscript on the previous
  // result. We conceptually view the previous result as an "anynomous base" 
  // from where to attach the underscript. Hence if the underscript is empty,
  // we should end up like <mover>. If the overscript is empty, we should
  // end up like <munder>.

  nsBoundingMetrics bmAnonymousBase = mBoundingMetrics;
  nscoord ascentAnonymousBase =
    std::max(mBoundingMetrics.ascent + overDelta2,
             overSize.BlockStartAscent() + bmOver.descent +
             overDelta1 + bmBase.ascent);
  ascentAnonymousBase = std::max(ascentAnonymousBase,
                                 baseSize.BlockStartAscent());

  // Width of non-spacing marks is zero so use left and right bearing.
  nscoord underWidth = bmUnder.width;
  if (!underWidth) {
    underWidth = bmUnder.rightBearing - bmUnder.leftBearing;
    dxUnder = -bmUnder.leftBearing;
  }

  nscoord maxWidth = std::max(bmAnonymousBase.width, underWidth);
  if (alignPosition == center &&
      !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
    GetItalicCorrection(bmAnonymousBase, correction);
    dxUnder += -correction/2;
  }
  nscoord dxAnonymousBase = 0;
  if (alignPosition == center) {
    dxUnder += (maxWidth - underWidth)/2;
    dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2;
  } else if (alignPosition == right) {
    dxUnder += maxWidth - underWidth;
    dxAnonymousBase = maxWidth - bmAnonymousBase.width;
  }

  // adjust the offsets of the real base and overscript since their
  // final offsets should be relative to us...
  dxOver += dxAnonymousBase;
  dxBase += dxAnonymousBase;

  mBoundingMetrics.width =
    std::max(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width);
  // At this point, mBoundingMetrics.ascent = bmAnonymousBase.ascent 
  mBoundingMetrics.descent = 
    bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent;
  mBoundingMetrics.leftBearing =
    std::min(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing);
  mBoundingMetrics.rightBearing = 
    std::max(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing);

  aDesiredSize.SetBlockStartAscent(ascentAnonymousBase);
  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
    std::max(mBoundingMetrics.descent + underDelta2,
           bmAnonymousBase.descent + underDelta1 + bmUnder.ascent +
             underSize.Height() - underSize.BlockStartAscent());
  aDesiredSize.Height() = std::max(aDesiredSize.Height(),
                               aDesiredSize.BlockStartAscent() +
                               baseSize.Height() - baseSize.BlockStartAscent());
  aDesiredSize.Width() = mBoundingMetrics.width;
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;

  mReference.x = 0;
  mReference.y = aDesiredSize.BlockStartAscent();

  if (aPlaceOrigin) {
    nscoord dy;
    // place overscript
    if (overFrame) {
      dy = aDesiredSize.BlockStartAscent() -
           mBoundingMetrics.ascent + bmOver.ascent -
           overSize.BlockStartAscent();
      FinishReflowChild (overFrame, PresContext(), overSize, nullptr, dxOver, dy, 0);
    }
    // place base
    dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
    FinishReflowChild (baseFrame, PresContext(), baseSize, nullptr, dxBase, dy, 0);
    // place underscript
    if (underFrame) {
      dy = aDesiredSize.BlockStartAscent() +
           mBoundingMetrics.descent - bmUnder.descent -
           underSize.BlockStartAscent();
      FinishReflowChild (underFrame, PresContext(), underSize, nullptr,
                         dxUnder, dy, 0);
    }
  }
  return NS_OK;
}
コード例 #11
0
void
nsSubDocumentFrame::Reflow(nsPresContext*           aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  MarkInReflow();
  DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
      aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));

  NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
               "Shouldn't have unconstrained stuff here "
               "thanks to the rules of reflow");
  NS_ASSERTION(NS_INTRINSICSIZE != aReflowState.ComputedHeight(),
               "Shouldn't have unconstrained stuff here "
               "thanks to ComputeAutoSize");

  aStatus = NS_FRAME_COMPLETE;

  NS_ASSERTION(mContent->GetPrimaryFrame() == this,
               "Shouldn't happen");

  // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
  aDesiredSize.SetSize(aReflowState.GetWritingMode(),
                       aReflowState.ComputedSizeWithBorderPadding());

  // "offset" is the offset of our content area from our frame's
  // top-left corner.
  nsPoint offset = nsPoint(aReflowState.ComputedPhysicalBorderPadding().left,
                           aReflowState.ComputedPhysicalBorderPadding().top);

  if (mInnerView) {
    const nsMargin& bp = aReflowState.ComputedPhysicalBorderPadding();
    nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
                     aDesiredSize.Height() - bp.TopBottom());

    // Size & position the view according to 'object-fit' & 'object-position'.
    nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
    IntrinsicSize intrinsSize;
    nsSize intrinsRatio;
    if (subDocRoot) {
      intrinsSize = subDocRoot->GetIntrinsicSize();
      intrinsRatio = subDocRoot->GetIntrinsicRatio();
    }
    nsRect destRect =
      nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize),
                                           intrinsSize, intrinsRatio,
                                           StylePosition());

    nsViewManager* vm = mInnerView->GetViewManager();
    vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
    vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
  }

  aDesiredSize.SetOverflowAreasToDesiredBounds();
  if (!ShouldClipSubdocument()) {
    nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
    if (subdocRootFrame) {
      aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
    }
  }

  FinishAndStoreOverflow(&aDesiredSize);

  if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
    PresContext()->PresShell()->PostReflowCallback(this);
    mPostedReflowCallback = true;
  }

  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
      aDesiredSize.Width(), aDesiredSize.Height(), aStatus));

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
コード例 #12
0
// exported routine that both munderover and mmultiscripts share.
// munderover uses this when movablelimits is set.
nsresult
nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext*      aPresContext,
                                        nsRenderingContext& aRenderingContext,
                                        bool                 aPlaceOrigin,
                                        nsHTMLReflowMetrics& aDesiredSize,
                                        nsMathMLContainerFrame* aFrame,
                                        nscoord              aUserSubScriptShift,
                                        nscoord              aUserSupScriptShift,
                                        nscoord              aScriptSpace)
{
  nsIAtom* tag = aFrame->GetContent()->Tag();

  // This function deals with both munderover etc. as well as msubsup etc.
  // As the former behaves identically to the later, we treat it as such
  // to avoid additional checks later.
  if (tag == nsGkAtoms::mover_)
    tag = nsGkAtoms::msup_;
  else if (tag == nsGkAtoms::munder_)
    tag = nsGkAtoms::msub_;
  else if (tag  == nsGkAtoms::munderover_)
    tag = nsGkAtoms::msubsup_;

  nsBoundingMetrics bmFrame;

  nscoord minShiftFromXHeight, subDrop, supDrop;

  ////////////////////////////////////////
  // Initialize super/sub shifts that
  // depend only on the current font
  ////////////////////////////////////////

  nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();

  if (!baseFrame) {
    if (tag == nsGkAtoms::mmultiscripts_)
      aFrame->ReportErrorToConsole("NoBase");
    else
      aFrame->ReportChildCountError();
    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
  }


  // get x-height (an ex)
  const nsStyleFont* font = aFrame->StyleFont();
  nsRefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
  aRenderingContext.SetFont(fm);

  nscoord xHeight = fm->XHeight();

  nscoord ruleSize;
  GetRuleThickness (aRenderingContext, fm, ruleSize);

  // force the scriptSpace to be at least 1 pixel
  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  aScriptSpace = std::max(onePixel, aScriptSpace);

  /////////////////////////////////////
  // first the shift for the subscript

  // subScriptShift{1,2}
  // = minimum amount to shift the subscript down
  // = sub{1,2} in TeXbook
  // subScriptShift1 = subscriptshift attribute * x-height
  nscoord subScriptShift1, subScriptShift2;

  // Get subScriptShift{1,2} default from font
  GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
  nscoord subScriptShift;
  if (tag == nsGkAtoms::msub_) {
    subScriptShift = subScriptShift1;
  } else {
    subScriptShift = std::max(subScriptShift1, subScriptShift2);
  }
  if (0 < aUserSubScriptShift) {
    // the user has set the subscriptshift attribute
    subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
  }

  /////////////////////////////////////
  // next the shift for the superscript

  // supScriptShift{1,2,3}
  // = minimum amount to shift the supscript up
  // = sup{1,2,3} in TeX
  // supScriptShift1 = superscriptshift attribute * x-height
  // Note that there are THREE values for supscript shifts depending
  // on the current style
  nscoord supScriptShift1, supScriptShift2, supScriptShift3;
  // Set supScriptShift{1,2,3} default from font
  GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);

  // get sup script shift depending on current script level and display style
  // Rule 18c, App. G, TeXbook
  nsPresentationData presentationData;
  aFrame->GetPresentationData(presentationData);
  nscoord supScriptShift;
  if (font->mScriptLevel == 0 &&
      font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
      !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
    // Style D in TeXbook
    supScriptShift = supScriptShift1;
  } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
    // Style C' in TeXbook = D',T',S',SS'
    supScriptShift = supScriptShift3;
  } else {
    // everything else = T,S,SS
    supScriptShift = supScriptShift2;
  }

  if (0 < aUserSupScriptShift) {
    // the user has set the supscriptshift attribute
    supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
  }

  ////////////////////////////////////
  // Get the children's sizes
  ////////////////////////////////////

  const WritingMode wm(aDesiredSize.GetWritingMode());
  nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
  nscoord minSubScriptShift = 0, minSupScriptShift = 0;
  nscoord trySubScriptShift = subScriptShift;
  nscoord trySupScriptShift = supScriptShift;
  nscoord maxSubScriptShift = subScriptShift;
  nscoord maxSupScriptShift = supScriptShift;
  nsHTMLReflowMetrics baseSize(wm);
  nsHTMLReflowMetrics subScriptSize(wm);
  nsHTMLReflowMetrics supScriptSize(wm);
  nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm);
  baseFrame = nullptr;
  nsIFrame* subScriptFrame = nullptr;
  nsIFrame* supScriptFrame = nullptr;
  nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.

  bool firstPrescriptsPair = false;
  nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
  multiSubSize.SetTopAscent(-0x7FFFFFFF);
  multiSupSize.SetTopAscent(-0x7FFFFFFF);
  bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
  bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
  nscoord italicCorrection = 0;

  nsBoundingMetrics boundingMetrics;
  boundingMetrics.width = 0;
  boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
  aDesiredSize.Width() = aDesiredSize.Height() = 0;

  int32_t count = 0;
  bool foundNoneTag = false;

  // Boolean to determine whether the current child is a subscript.
  // Note that only msup starts with a superscript.
  bool isSubScript = (tag != nsGkAtoms::msup_);

  nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
  while (childFrame) {
    nsIAtom* childTag = childFrame->GetContent()->Tag();
    if (childTag == nsGkAtoms::mprescripts_) {
      if (tag != nsGkAtoms::mmultiscripts_) {
        if (aPlaceOrigin) {
          aFrame->ReportInvalidChildError(childTag);
        }
        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
      }
      if (prescriptsFrame) {
        // duplicate <mprescripts/> found
        // report an error, encourage people to get their markups in order
        if (aPlaceOrigin) {
          aFrame->ReportErrorToConsole("DuplicateMprescripts");
        }
        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
      }
      if (!isSubScript) {
        if (aPlaceOrigin) {
          aFrame->ReportErrorToConsole("SubSupMismatch");
        }
        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
      }

      prescriptsFrame = childFrame;
      firstPrescriptsPair = true;
    } else if (0 == count) {
      // base

      if (childTag == nsGkAtoms::none) {
        if (tag == nsGkAtoms::mmultiscripts_) {
          if (aPlaceOrigin) {
            aFrame->ReportErrorToConsole("NoBase");
          }
          return aFrame->ReflowError(aRenderingContext, aDesiredSize);
        } else {
          //A different error message is triggered later for the other tags
          foundNoneTag = true;
        }
      }
      baseFrame = childFrame;
      GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);

      if (tag != nsGkAtoms::msub_) {
        // Apply italics correction if there is the potential for a 
        // postsupscript.
        GetItalicCorrection(bmBase, italicCorrection);
        // If italics correction is applied, we always add "a little to spare"
        // (see TeXbook Ch.11, p.64), as we estimate the italic creation
        // ourselves and it isn't the same as TeX.
        italicCorrection += onePixel;
      }

      // we update boundingMetrics.{ascent,descent} with that
      // of the baseFrame only after processing all the sup/sub pairs
      boundingMetrics.width = bmBase.width;
      boundingMetrics.rightBearing = bmBase.rightBearing;
      boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
    } else {
      // super/subscript block
      if ( childTag == nsGkAtoms::none) {
        foundNoneTag = true;
      }

      if (isSubScript) {
        // subscript
        subScriptFrame = childFrame;
        GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
        // get the subdrop from the subscript font
        GetSubDropFromChild (subScriptFrame, subDrop);
        // parameter v, Rule 18a, App. G, TeXbook
        minSubScriptShift = bmBase.descent + subDrop;
        trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
        multiSubSize.SetTopAscent(std::max(multiSubSize.TopAscent(),
                                       subScriptSize.TopAscent()));
        bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
        bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
        multiSubSize.Height() = 
          std::max(multiSubSize.Height(),
                   subScriptSize.Height() - subScriptSize.TopAscent());
        if (bmSubScript.width)
          width = bmSubScript.width + aScriptSpace;
        rightBearing = bmSubScript.rightBearing;

        if (tag == nsGkAtoms::msub_) {
          boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
          boundingMetrics.width += width;

          // get min subscript shift limit from x-height
          // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
          nscoord minShiftFromXHeight = (nscoord) 
            (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
          maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);

          maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
          trySubScriptShift = subScriptShift;
        }
      } else {
        // supscript
        supScriptFrame = childFrame;
        GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
        // get the supdrop from the supscript font
        GetSupDropFromChild (supScriptFrame, supDrop);
        // parameter u, Rule 18a, App. G, TeXbook
        minSupScriptShift = bmBase.ascent - supDrop;
        // get min supscript shift limit from x-height
        // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
        minShiftFromXHeight = NSToCoordRound
          ((bmSupScript.descent + (1.0f/4.0f) * xHeight));
        trySupScriptShift = std::max(minSupScriptShift,
                                     std::max(minShiftFromXHeight,
                                              supScriptShift));
        multiSupSize.SetTopAscent(std::max(multiSupSize.TopAscent(),
                                       supScriptSize.TopAscent()));
        bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
        bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
        multiSupSize.Height() = 
          std::max(multiSupSize.Height(),
                   supScriptSize.Height() - supScriptSize.TopAscent());

        if (bmSupScript.width)
          width = std::max(width, bmSupScript.width + aScriptSpace);

        if (!prescriptsFrame) { // we are still looping over base & postscripts
          rightBearing = std::max(rightBearing,
                                  italicCorrection + bmSupScript.rightBearing);
          boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
          boundingMetrics.width += width;
        } else {
          prescriptsWidth += width;
          if (firstPrescriptsPair) {
            firstPrescriptsPair = false;
            boundingMetrics.leftBearing =
              std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
          }
        }
        width = rightBearing = 0;

        // negotiate between the various shifts so that
        // there is enough gap between the sup and subscripts
        // Rule 18e, App. G, TeXbook
        if (tag == nsGkAtoms::mmultiscripts_ || 
            tag == nsGkAtoms::msubsup_) {
          nscoord gap =
            (trySupScriptShift - bmSupScript.descent) -
            (bmSubScript.ascent - trySubScriptShift);
          if (gap < 4.0f * ruleSize) {
            // adjust trySubScriptShift to get a gap of (4.0 * ruleSize)
            trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap);
          }

          // next we want to ensure that the bottom of the superscript
          // will be > (4/5) * x-height above baseline
          gap = NSToCoordRound ((4.0f/5.0f) * xHeight -
                  (trySupScriptShift - bmSupScript.descent));
          if (gap > 0) {
            trySupScriptShift += gap;
            trySubScriptShift -= gap;
          }
        }

        maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
        maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);

        trySubScriptShift = subScriptShift;
        trySupScriptShift = supScriptShift;
      }

      isSubScript = !isSubScript;
    }
    count++;
    childFrame = childFrame->GetNextSibling();
  }

  //NoBase error may also have been reported above
  if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) ||
      (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame ||
      (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
      (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
    // report an error, encourage people to get their markups in order
    if (aPlaceOrigin) {
      if ((count != 2 && (tag == nsGkAtoms::msup_ || 
          tag == nsGkAtoms::msub_)) ||
          (count != 3 && tag == nsGkAtoms::msubsup_ )) {
        aFrame->ReportChildCountError();
      } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
        aFrame->ReportInvalidChildError(nsGkAtoms::none);
      } else if (!baseFrame) {
        aFrame->ReportErrorToConsole("NoBase");
      } else {
        aFrame->ReportErrorToConsole("SubSupMismatch");
      }
    }
    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
  }

  // we left out the width of prescripts, so ...
  boundingMetrics.rightBearing += prescriptsWidth;
  boundingMetrics.width += prescriptsWidth;

  // Zero out the shifts in where a frame isn't present to avoid the potential
  // for overflow.
  if (!subScriptFrame)
    maxSubScriptShift = 0;
  if (!supScriptFrame)
    maxSupScriptShift = 0;

  // we left out the base during our bounding box updates, so ...
  if (tag == nsGkAtoms::msub_) {
    boundingMetrics.ascent = std::max(bmBase.ascent,
                                      bmMultiSub.ascent - maxSubScriptShift);
  } else {
    boundingMetrics.ascent =
      std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
  }
  if (tag == nsGkAtoms::msup_) {
    boundingMetrics.descent = std::max(bmBase.descent,
                                       bmMultiSup.descent - maxSupScriptShift);
  } else {
    boundingMetrics.descent =
      std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
  }
  aFrame->SetBoundingMetrics(boundingMetrics);

  // get the reflow metrics ...
  aDesiredSize.SetTopAscent( 
    std::max(baseSize.TopAscent(), 
             std::max(multiSubSize.TopAscent() - maxSubScriptShift,
                      multiSupSize.TopAscent() + maxSupScriptShift)));
  aDesiredSize.Height() = aDesiredSize.TopAscent() +
    std::max(baseSize.Height() - baseSize.TopAscent(),
             std::max(multiSubSize.Height() + maxSubScriptShift,
                      multiSupSize.Height() - maxSupScriptShift));
  aDesiredSize.Width() = boundingMetrics.width;
  aDesiredSize.mBoundingMetrics = boundingMetrics;

  aFrame->SetReference(nsPoint(0, aDesiredSize.TopAscent()));

  //////////////////
  // Place Children

  // Place prescripts, followed by base, and then postscripts.
  // The list of frames is in the order: {base} {postscripts} {prescripts}
  // We go over the list in a circular manner, starting at <prescripts/>

  if (aPlaceOrigin) {
    nscoord dx = 0, dy = 0;

    // With msub and msup there is only one element and 
    // subscriptFrame/supScriptFrame have already been set above where
    // relevant.  In these cases we skip to the reflow part.
    if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
      count = 1;
    else
      count = 0;
    childFrame = prescriptsFrame;
    bool isPreScript = true;
    do {
      if (!childFrame) { // end of prescripts,
        isPreScript = false;
        // place the base ...
        childFrame = baseFrame;
        dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
        FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
                           aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                               baseSize.Width(),
                                               dx),
                           dy, 0);
        dx += bmBase.width;
      } else if (prescriptsFrame != childFrame) {
        // process each sup/sub pair
        if (0 == count) {
          subScriptFrame = childFrame;
          count = 1;
        } else if (1 == count) {
          if (tag != nsGkAtoms::msub_)
            supScriptFrame = childFrame;
          count = 0;

          // get the ascent/descent of sup/subscripts stored in their rects
          // rect.x = descent, rect.y = ascent
          if (subScriptFrame)
            GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
          if (supScriptFrame)
            GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);

          width = std::max(subScriptSize.Width(), supScriptSize.Width());

          if (subScriptFrame) {
            nscoord x = dx;
            // prescripts should be right aligned
            // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
            if (isPreScript)
              x += width - subScriptSize.Width();
            dy = aDesiredSize.TopAscent() - subScriptSize.TopAscent() +
              maxSubScriptShift;
            FinishReflowChild (subScriptFrame, aPresContext, subScriptSize,
                               nullptr,
                               aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                   subScriptSize.Width(),
                                                   x),
                               dy, 0);
          }

          if (supScriptFrame) {
            nscoord x = dx;
            if (isPreScript) {
              x += width - supScriptSize.Width();
            } else {
              // post superscripts are shifted by the italic correction value
              x += italicCorrection;
            }
            dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() -
              maxSupScriptShift;
            FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
                               nullptr,
                               aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                   supScriptSize.Width(),
                                                   x),
                               dy, 0);
          }
          dx += width + aScriptSpace;
        }
      }
      childFrame = childFrame->GetNextSibling();
    } while (prescriptsFrame != childFrame);
  }

  return NS_OK;
}
コード例 #13
0
nsresult
nsNumberControlFrame::Reflow(nsPresContext* aPresContext,
                             nsHTMLReflowMetrics& aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus& aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsNumberControlFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  NS_ASSERTION(mOuterWrapper, "Outer wrapper div must exist!");

  NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
               "nsNumberControlFrame should not have continuations; if it does we "
               "need to call RegUnregAccessKey only for the first");

  NS_ASSERTION(!mFrames.FirstChild() ||
               !mFrames.FirstChild()->GetNextSibling(),
               "We expect at most one direct child frame");

  if (mState & NS_FRAME_FIRST_REFLOW) {
    nsFormControlFrame::RegUnRegAccessKey(this, true);
  }

  // The width of our content box, which is the available width
  // for our anonymous content:
  const nscoord contentBoxWidth = aReflowState.ComputedWidth();
  nscoord contentBoxHeight = aReflowState.ComputedHeight();

  nsIFrame* outerWrapperFrame = mOuterWrapper->GetPrimaryFrame();

  if (!outerWrapperFrame) { // display:none?
    if (contentBoxHeight == NS_INTRINSICSIZE) {
      contentBoxHeight = 0;
    }
  } else {
    NS_ASSERTION(outerWrapperFrame == mFrames.FirstChild(), "huh?");

    nsHTMLReflowMetrics wrappersDesiredSize(aReflowState.GetWritingMode());

    nsHTMLReflowState wrapperReflowState(aPresContext, aReflowState,
                                         outerWrapperFrame,
                                         nsSize(contentBoxWidth,
                                                NS_UNCONSTRAINEDSIZE));

    // offsets of wrapper frame
    nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left +
                        wrapperReflowState.ComputedPhysicalMargin().left;
    nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top +
                        wrapperReflowState.ComputedPhysicalMargin().top;

    nsReflowStatus childStatus;
    nsresult rv = ReflowChild(outerWrapperFrame, aPresContext,
                              wrappersDesiredSize, wrapperReflowState,
                              xoffset, yoffset, 0, childStatus);
    NS_ENSURE_SUCCESS(rv, rv);
    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
               "We gave our child unconstrained height, so it should be complete");

    nscoord wrappersMarginBoxHeight = wrappersDesiredSize.Height() +
      wrapperReflowState.ComputedPhysicalMargin().TopBottom();

    if (contentBoxHeight == NS_INTRINSICSIZE) {
      // We are intrinsically sized -- we should shrinkwrap the outer wrapper's
      // height:
      contentBoxHeight = wrappersMarginBoxHeight;

      // Make sure we obey min/max-height in the case when we're doing intrinsic
      // sizing (we get it for free when we have a non-intrinsic
      // aReflowState.ComputedHeight()).  Note that we do this before
      // adjusting for borderpadding, since mComputedMaxHeight and
      // mComputedMinHeight are content heights.
      contentBoxHeight =
        NS_CSS_MINMAX(contentBoxHeight,
                      aReflowState.ComputedMinHeight(),
                      aReflowState.ComputedMaxHeight());
    }

    // Center child vertically
    nscoord extraSpace = contentBoxHeight - wrappersMarginBoxHeight;
    yoffset += std::max(0, extraSpace / 2);

    // Place the child
    rv = FinishReflowChild(outerWrapperFrame, aPresContext,
                           wrappersDesiredSize, &wrapperReflowState,
                           xoffset, yoffset, 0);
    NS_ENSURE_SUCCESS(rv, rv);

    aDesiredSize.SetTopAscent(wrappersDesiredSize.TopAscent() +
                              outerWrapperFrame->GetPosition().y);
  }

  aDesiredSize.Width() = contentBoxWidth +
                         aReflowState.ComputedPhysicalBorderPadding().LeftRight();
  aDesiredSize.Height() = contentBoxHeight +
                          aReflowState.ComputedPhysicalBorderPadding().TopBottom();

  aDesiredSize.SetOverflowAreasToDesiredBounds();

  if (outerWrapperFrame) {
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, outerWrapperFrame);
  }

  FinishAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);

  return NS_OK;
}
コード例 #14
0
void
nsMathMLmrootFrame::Reflow(nsPresContext*          aPresContext,
                           nsHTMLReflowMetrics&     aDesiredSize,
                           const nsHTMLReflowState& aReflowState,
                           nsReflowStatus&          aStatus)
{
  MarkInReflow();
  nsReflowStatus childStatus;

  mPresentationData.flags &= ~NS_MATHML_ERROR;
  aDesiredSize.ClearSize();
  aDesiredSize.SetBlockStartAscent(0);

  nsBoundingMetrics bmSqr, bmBase, bmIndex;
  DrawTarget* drawTarget = aReflowState.rendContext->GetDrawTarget();

  //////////////////
  // Reflow Children

  int32_t count = 0;
  nsIFrame* baseFrame = nullptr;
  nsIFrame* indexFrame = nullptr;
  nsHTMLReflowMetrics baseSize(aReflowState);
  nsHTMLReflowMetrics indexSize(aReflowState);
  nsIFrame* childFrame = mFrames.FirstChild();
  while (childFrame) {
    // ask our children to compute their bounding metrics 
    nsHTMLReflowMetrics childDesiredSize(aReflowState,
                                         aDesiredSize.mFlags
                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
    WritingMode wm = childFrame->GetWritingMode();
    LogicalSize availSize = aReflowState.ComputedSize(wm);
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    ReflowChild(childFrame, aPresContext,
                     childDesiredSize, childReflowState, childStatus);
    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
    if (0 == count) {
      // base 
      baseFrame = childFrame;
      baseSize = childDesiredSize;
      bmBase = childDesiredSize.mBoundingMetrics;
    }
    else if (1 == count) {
      // index
      indexFrame = childFrame;
      indexSize = childDesiredSize;
      bmIndex = childDesiredSize.mBoundingMetrics;
    }
    count++;
    childFrame = childFrame->GetNextSibling();
  }
  if (2 != count) {
    // report an error, encourage people to get their markups in order
    ReportChildCountError();
    ReflowError(drawTarget, aDesiredSize);
    aStatus = NS_FRAME_COMPLETE;
    NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
    // Call DidReflow() for the child frames we successfully did reflow.
    DidReflowChildren(mFrames.FirstChild(), childFrame);
    return;
  }

  ////////////
  // Prepare the radical symbol and the overline bar

  RefPtr<nsFontMetrics> fm;
  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                        fontSizeInflation);

  nscoord ruleThickness, leading, psi;
  GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
                       NS_MATHML_DISPLAYSTYLE_BLOCK,
                       ruleThickness, leading, psi);

  // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
  char16_t one = '1';
  nsBoundingMetrics bmOne =
    nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, drawTarget);
  if (bmOne.ascent > bmBase.ascent)
    psi += bmOne.ascent - bmBase.ascent;

  // make sure that the rule appears on on screen
  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  if (ruleThickness < onePixel) {
    ruleThickness = onePixel;
  }

  // adjust clearance psi to get an exact number of pixels -- this
  // gives a nicer & uniform look on stacked radicals (bug 130282)
  nscoord delta = psi % onePixel;
  if (delta)
    psi += onePixel - delta; // round up

  // Stretch the radical symbol to the appropriate height if it is not big enough.
  nsBoundingMetrics contSize = bmBase;
  contSize.descent = bmBase.ascent + bmBase.descent + psi;
  contSize.ascent = ruleThickness;

  // height(radical) should be >= height(base) + psi + ruleThickness
  nsBoundingMetrics radicalSize;
  mSqrChar.Stretch(aPresContext, drawTarget,
                   fontSizeInflation,
                   NS_STRETCH_DIRECTION_VERTICAL, 
                   contSize, radicalSize,
                   NS_STRETCH_LARGER,
                   StyleVisibility()->mDirection);
  // radicalSize have changed at this point, and should match with
  // the bounding metrics of the char
  mSqrChar.GetBoundingMetrics(bmSqr);

  // Update the desired size for the container (like msqrt, index is not yet included)
  // the baseline will be that of the base.
  mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness;
  mBoundingMetrics.descent = 
    std::max(bmBase.descent,
           (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent));
  mBoundingMetrics.width = bmSqr.width + bmBase.width;
  mBoundingMetrics.leftBearing = bmSqr.leftBearing;
  mBoundingMetrics.rightBearing = bmSqr.width + 
    std::max(bmBase.width, bmBase.rightBearing); // take also care of the rule

  aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
    std::max(baseSize.Height() - baseSize.BlockStartAscent(),
             mBoundingMetrics.descent + ruleThickness);
  aDesiredSize.Width() = mBoundingMetrics.width;

  /////////////
  // Re-adjust the desired size to include the index.
  
  // the index is raised by some fraction of the height
  // of the radical, see \mroot macro in App. B, TexBook
  float raiseIndexPercent = 0.6f;
  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
  if (mathFont) {
    raiseIndexPercent =
      mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent);
  }
  nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent *
                                           (bmSqr.ascent + bmSqr.descent));
  nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical 
    - (bmSqr.ascent + bmSqr.descent) // to bottom of radical
    + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index

  nscoord indexClearance = 0;
  if (mBoundingMetrics.ascent < indexRaisedAscent) {
    indexClearance = 
      indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index 
    mBoundingMetrics.ascent = indexRaisedAscent;
    nscoord descent = aDesiredSize.Height() - aDesiredSize.BlockStartAscent();
    aDesiredSize.SetBlockStartAscent(mBoundingMetrics.ascent + leading);
    aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + descent;
  }

  nscoord dxIndex, dxSqr;
  GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr);

  mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width;
  mBoundingMetrics.leftBearing = 
    std::min(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing);
  mBoundingMetrics.rightBearing = dxSqr + bmSqr.width +
    std::max(bmBase.width, bmBase.rightBearing);

  aDesiredSize.Width() = mBoundingMetrics.width;
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  GatherAndStoreOverflow(&aDesiredSize);

  // place the index
  nscoord dx = dxIndex;
  nscoord dy = aDesiredSize.BlockStartAscent() -
    (indexRaisedAscent + indexSize.BlockStartAscent() - bmIndex.ascent);
  FinishReflowChild(indexFrame, aPresContext, indexSize, nullptr,
                    MirrorIfRTL(aDesiredSize.Width(), indexSize.Width(), dx),
                    dy, 0);

  // place the radical symbol and the radical bar
  dx = dxSqr;
  dy = indexClearance + leading; // leave a leading at the top
  mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.Width(), bmSqr.width, dx),
                          dy, bmSqr.width, bmSqr.ascent + bmSqr.descent));
  dx += bmSqr.width;
  mBarRect.SetRect(MirrorIfRTL(aDesiredSize.Width(), bmBase.width, dx),
                   dy, bmBase.width, ruleThickness);

  // place the base
  dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
  FinishReflowChild(baseFrame, aPresContext, baseSize, nullptr,
                    MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx),
                    dy, 0);

  mReference.x = 0;
  mReference.y = aDesiredSize.BlockStartAscent();

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
コード例 #15
0
void
nsCanvasFrame::Reflow(nsPresContext*           aPresContext,
                      nsHTMLReflowMetrics&     aDesiredSize,
                      const nsHTMLReflowState& aReflowState,
                      nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow");

  // Initialize OUT parameter
  aStatus = NS_FRAME_COMPLETE;

  nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*>
                                               (GetPrevInFlow());
  if (prevCanvasFrame) {
    AutoFrameListPtr overflow(aPresContext,
                              prevCanvasFrame->StealOverflowFrames());
    if (overflow) {
      NS_ASSERTION(overflow->OnlyChild(),
                   "must have doc root as canvas frame's only child");
      nsContainerFrame::ReparentFrameViewList(*overflow, prevCanvasFrame, this);
      // Prepend overflow to the our child list. There may already be
      // children placeholders for fixed-pos elements, which don't get
      // reflowed but must not be lost until the canvas frame is destroyed.
      mFrames.InsertFrames(this, nullptr, *overflow);
    }
  }

  // Set our size up front, since some parts of reflow depend on it
  // being already set.  Note that the computed height may be
  // unconstrained; that's ok.  Consumers should watch out for that.
  SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); 

  // Reflow our one and only normal child frame. It's either the root
  // element's frame or a placeholder for that frame, if the root element
  // is abs-pos or fixed-pos. We may have additional children which
  // are placeholders for continuations of fixed-pos content, but those
  // don't need to be reflowed. The normal child is always comes before
  // the fixed-pos placeholders, because we insert it at the start
  // of the child list, above.
  nsHTMLReflowMetrics kidDesiredSize(aReflowState);
  if (mFrames.IsEmpty()) {
    // We have no child frame, so return an empty size
    aDesiredSize.Width() = aDesiredSize.Height() = 0;
  } else {
    nsIFrame* kidFrame = mFrames.FirstChild();
    bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;

    nsHTMLReflowState
      kidReflowState(aPresContext, aReflowState, kidFrame,
                     aReflowState.AvailableSize(kidFrame->GetWritingMode()));

    if (aReflowState.mFlags.mVResize &&
        (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
      // Tell our kid it's being vertically resized too.  Bit of a
      // hack for framesets.
      kidReflowState.mFlags.mVResize = true;
    }

    nsPoint kidPt(kidReflowState.ComputedPhysicalMargin().left,
                  kidReflowState.ComputedPhysicalMargin().top);

    kidReflowState.ApplyRelativePositioning(&kidPt);

    // Reflow the frame
    ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
                kidPt.x, kidPt.y, 0, aStatus);

    // Complete the reflow and position and size the child frame
    FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, &kidReflowState,
                      kidPt.x, kidPt.y, 0);

    if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
      nsIFrame* nextFrame = kidFrame->GetNextInFlow();
      NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
        "If it's incomplete and has no nif yet, it must flag a nif reflow.");
      if (!nextFrame) {
        nextFrame = aPresContext->PresShell()->FrameConstructor()->
          CreateContinuingFrame(aPresContext, kidFrame, this);
        SetOverflowFrames(nsFrameList(nextFrame, nextFrame));
        // Root overflow containers will be normal children of
        // the canvas frame, but that's ok because there
        // aren't any other frames we need to isolate them from
        // during reflow.
      }
      if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
        nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
      }
    }

    // If the child frame was just inserted, then we're responsible for making sure
    // it repaints
    if (kidDirty) {
      // But we have a new child, which will affect our background, so
      // invalidate our whole rect.
      // Note: Even though we request to be sized to our child's size, our
      // scroll frame ensures that we are always the size of the viewport.
      // Also note: GetPosition() on a CanvasFrame is always going to return
      // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect()
      // could also include overflow to our top and left (out of the viewport)
      // which doesn't need to be painted.
      nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
      viewport->InvalidateFrame();
    }
    
    // Return our desired size. Normally it's what we're told, but
    // sometimes we can be given an unconstrained height (when a window
    // is sizing-to-content), and we should compute our desired height.
    WritingMode wm = aReflowState.GetWritingMode();
    LogicalSize finalSize(wm);
    finalSize.ISize(wm) = aReflowState.ComputedISize();
    if (aReflowState.ComputedBSize() == NS_UNCONSTRAINEDSIZE) {
      finalSize.BSize(wm) = kidFrame->GetLogicalSize(wm).BSize(wm) +
        kidReflowState.ComputedLogicalMargin().BStartEnd(wm);
    } else {
      finalSize.BSize(wm) = aReflowState.ComputedBSize();
    }

    aDesiredSize.SetSize(wm, finalSize);
    aDesiredSize.SetOverflowAreasToDesiredBounds();
    aDesiredSize.mOverflowAreas.UnionWith(
      kidDesiredSize.mOverflowAreas + kidPt);
  }

  if (prevCanvasFrame) {
    ReflowOverflowContainerChildren(aPresContext, aReflowState,
                                    aDesiredSize.mOverflowAreas, 0,
                                    aStatus);
  }

  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);

  NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus);
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
}
コード例 #16
0
ファイル: nsInlineFrame.cpp プロジェクト: tefn3849/gecko-dev
void
nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
                            const nsHTMLReflowState& aReflowState,
                            InlineReflowState& irs,
                            nsHTMLReflowMetrics& aMetrics,
                            nsReflowStatus& aStatus)
{
  aStatus = NS_FRAME_COMPLETE;

  nsLineLayout* lineLayout = aReflowState.mLineLayout;
  bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
  RestyleManager* restyleManager = aPresContext->RestyleManager();
  WritingMode frameWM = aReflowState.GetWritingMode();
  WritingMode lineWM = aReflowState.mLineLayout->mRootSpan->mWritingMode;
  LogicalMargin framePadding = aReflowState.ComputedLogicalBorderPadding();
  nscoord startEdge = 0;
  const bool boxDecorationBreakClone =
    MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
                   NS_STYLE_BOX_DECORATION_BREAK_CLONE);
  // Don't offset by our start borderpadding if we have a prev continuation or
  // if we're in a part of an {ib} split other than the first one. For
  // box-decoration-break:clone we always offset our start since all
  // continuations have border/padding.
  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
      boxDecorationBreakClone) {
    startEdge = framePadding.IStart(frameWM);
  }
  nscoord availableISize = aReflowState.AvailableISize();
  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
               "should no longer use available widths");
  // Subtract off inline axis border+padding from availableISize
  availableISize -= startEdge;
  availableISize -= framePadding.IEnd(frameWM);
  lineLayout->BeginSpan(this, &aReflowState, startEdge,
                        startEdge + availableISize, &mBaseline);

  // First reflow our principal children.
  nsIFrame* frame = mFrames.FirstChild();
  bool done = false;
  while (frame) {
    // Check if we should lazily set the child frame's parent pointer.
    if (irs.mSetParentPointer) {
      bool havePrevBlock =
        irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
      nsIFrame* child = frame;
      do {
        // If our block is the first in flow, then any floats under the pulled
        // frame must already belong to our block.
        if (havePrevBlock) {
          // This has to happen before we update frame's parent; we need to
          // know frame's ancestry under its old block.
          // The blockChildren.ContainsFrame check performed by
          // ReparentFloatsForInlineChild here may be slow, but we can't
          // easily avoid it because we don't know where 'frame' originally
          // came from. If we really really have to optimize this we could
          // cache whether frame->GetParent() is under its containing blocks
          // overflowList or not.
          ReparentFloatsForInlineChild(irs.mLineContainer, child, false);
        }
        child->SetParent(this);
        if (inFirstLine) {
          restyleManager->ReparentStyleContext(child);
          nsLayoutUtils::MarkDescendantsDirty(child);
        }
        // We also need to do the same for |frame|'s next-in-flows that are in
        // the sibling list. Otherwise, if we reflow |frame| and it's complete
        // we'll crash when trying to delete its next-in-flow.
        // This scenario doesn't happen often, but it can happen.
        nsIFrame* nextSibling = child->GetNextSibling();
        child = child->GetNextInFlow();
        if (MOZ_UNLIKELY(child)) {
          while (child != nextSibling && nextSibling) {
            nextSibling = nextSibling->GetNextSibling();
          }
          if (!nextSibling) {
            child = nullptr;
          }
        }
        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
      } while (child);

      // Fix the parent pointer for ::first-letter child frame next-in-flows,
      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
      if (realFrame->GetType() == nsGkAtoms::letterFrame) {
        nsIFrame* child = realFrame->GetFirstPrincipalChild();
        if (child) {
          NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
                       "unexpected frame type");
          nsIFrame* nextInFlow = child->GetNextInFlow();
          for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
            NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame,
                         "unexpected frame type");
            if (mFrames.ContainsFrame(nextInFlow)) {
              nextInFlow->SetParent(this);
              if (inFirstLine) {
                restyleManager->ReparentStyleContext(nextInFlow);
                nsLayoutUtils::MarkDescendantsDirty(nextInFlow);
              }
            }
            else {
#ifdef DEBUG              
              // Once we find a next-in-flow that isn't ours none of the
              // remaining next-in-flows should be either.
              for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
                             "unexpected letter frame flow");
              }
#endif
              break;
            }
          }
        }
      }
    }
    MOZ_ASSERT(frame->GetParent() == this);

    if (!done) {
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
      ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
      done = NS_INLINE_IS_BREAK(aStatus) || 
             (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus));
      if (done) {
        if (!irs.mSetParentPointer) {
          break;
        }
        // Keep reparenting the remaining siblings, but don't reflow them.
        nsFrameList* pushedFrames = GetOverflowFrames();
        if (pushedFrames && pushedFrames->FirstChild() == frame) {
          // Don't bother if |frame| was pushed to our overflow list.
          break;
        }
      } else {
        irs.mPrevFrame = frame;
      }
    }
    frame = frame->GetNextSibling();
  }

  // Attempt to pull frames from our next-in-flow until we can't
  if (!done && GetNextInFlow()) {
    while (true) {
      bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
      bool isComplete;
      if (!frame) { // Could be non-null if we pulled a first-letter frame and
                    // it created a continuation, since we don't push those.
        frame = PullOneFrame(aPresContext, irs, &isComplete);
      }
#ifdef NOISY_PUSHING
      printf("%p pulled up %p\n", this, frame);
#endif
      if (nullptr == frame) {
        if (!isComplete) {
          aStatus = NS_FRAME_NOT_COMPLETE;
        }
        break;
      }
      ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
      if (NS_INLINE_IS_BREAK(aStatus) || 
          (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
        break;
      }
      irs.mPrevFrame = frame;
      frame = frame->GetNextSibling();
    }
  }

  NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) || !GetOverflowFrames(),
               "We can't be complete AND have overflow frames!");

  // If after reflowing our children they take up no area then make
  // sure that we don't either.
  //
  // Note: CSS demands that empty inline elements still affect the
  // line-height calculations. However, continuations of an inline
  // that are empty we force to empty so that things like collapsed
  // whitespace in an inline element don't affect the line-height.
  aMetrics.ISize(lineWM) = lineLayout->EndSpan(this);

  // Compute final width.

  // XXX Note that that the padding start and end are in the frame's
  //     writing mode, but the metrics' inline-size is in the line's
  //     writing mode. This makes sense if the line and frame are both
  //     vertical or both horizontal, but what should happen with
  //     orthogonal inlines?

  // Make sure to not include our start border and padding if we have a prev
  // continuation or if we're in a part of an {ib} split other than the first
  // one.  For box-decoration-break:clone we always include our start border
  // and padding since all continuations have them.
  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
      boxDecorationBreakClone) {
    aMetrics.ISize(lineWM) += framePadding.IStart(frameWM);
  }

  /*
   * We want to only apply the end border and padding if we're the last
   * continuation and either not in an {ib} split or the last part of it.  To
   * be the last continuation we have to be complete (so that we won't get a
   * next-in-flow) and have no non-fluid continuations on our continuation
   * chain.  For box-decoration-break:clone we always apply the end border and
   * padding since all continuations have them.
   */
  if ((NS_FRAME_IS_COMPLETE(aStatus) &&
       !LastInFlow()->GetNextContinuation() &&
       !FrameIsNonLastInIBSplit()) ||
      boxDecorationBreakClone) {
    aMetrics.ISize(lineWM) += framePadding.IEnd(frameWM);
  }

  nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics,
                                         framePadding, lineWM, frameWM);

  // For now our overflow area is zero. The real value will be
  // computed in |nsLineLayout::RelativePositionFrames|.
  aMetrics.mOverflowAreas.Clear();

#ifdef NOISY_FINAL_SIZE
  ListTag(stdout);
  printf(": metrics=%d,%d ascent=%d\n",
         aMetrics.Width(), aMetrics.Height(), aMetrics.TopAscent());
#endif
}