layout/mathml/nsMathMLmencloseFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/mathml/nsMathMLmencloseFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,826 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsMathMLmencloseFrame.h"
    1.10 +#include "nsPresContext.h"
    1.11 +#include "nsRenderingContext.h"
    1.12 +#include "nsWhitespaceTokenizer.h"
    1.13 +
    1.14 +#include "nsDisplayList.h"
    1.15 +#include "gfxContext.h"
    1.16 +#include "nsMathMLChar.h"
    1.17 +#include <algorithm>
    1.18 +
    1.19 +//
    1.20 +// <menclose> -- enclose content with a stretching symbol such
    1.21 +// as a long division sign. - implementation
    1.22 +
    1.23 +// longdiv:
    1.24 +// Unicode 5.1 assigns U+27CC to LONG DIVISION, but a right parenthesis
    1.25 +// renders better with current font support.
    1.26 +static const char16_t kLongDivChar = ')';
    1.27 +
    1.28 +// radical: 'SQUARE ROOT'
    1.29 +static const char16_t kRadicalChar = 0x221A;
    1.30 +
    1.31 +// updiagonalstrike
    1.32 +static const uint8_t kArrowHeadSize = 10;
    1.33 +
    1.34 +nsIFrame*
    1.35 +NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.36 +{
    1.37 +  return new (aPresShell) nsMathMLmencloseFrame(aContext);
    1.38 +}
    1.39 +
    1.40 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmencloseFrame)
    1.41 +
    1.42 +nsMathMLmencloseFrame::nsMathMLmencloseFrame(nsStyleContext* aContext) :
    1.43 +  nsMathMLContainerFrame(aContext), mNotationsToDraw(0),
    1.44 +  mLongDivCharIndex(-1), mRadicalCharIndex(-1), mContentWidth(0)
    1.45 +{
    1.46 +}
    1.47 +
    1.48 +nsMathMLmencloseFrame::~nsMathMLmencloseFrame()
    1.49 +{
    1.50 +}
    1.51 +
    1.52 +nsresult nsMathMLmencloseFrame::AllocateMathMLChar(nsMencloseNotation mask)
    1.53 +{
    1.54 +  // Is the char already allocated?
    1.55 +  if ((mask == NOTATION_LONGDIV && mLongDivCharIndex >= 0) ||
    1.56 +      (mask == NOTATION_RADICAL && mRadicalCharIndex >= 0))
    1.57 +    return NS_OK;
    1.58 +
    1.59 +  // No need to track the style context given to our MathML chars.
    1.60 +  // The Style System will use Get/SetAdditionalStyleContext() to keep it
    1.61 +  // up-to-date if dynamic changes arise.
    1.62 +  uint32_t i = mMathMLChar.Length();
    1.63 +  nsAutoString Char;
    1.64 +
    1.65 +  if (!mMathMLChar.AppendElement())
    1.66 +    return NS_ERROR_OUT_OF_MEMORY;
    1.67 +
    1.68 +  if (mask == NOTATION_LONGDIV) {
    1.69 +    Char.Assign(kLongDivChar);
    1.70 +    mLongDivCharIndex = i;
    1.71 +  } else if (mask == NOTATION_RADICAL) {
    1.72 +    Char.Assign(kRadicalChar);
    1.73 +    mRadicalCharIndex = i;
    1.74 +  }
    1.75 +
    1.76 +  nsPresContext *presContext = PresContext();
    1.77 +  mMathMLChar[i].SetData(presContext, Char);
    1.78 +  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar[i]);
    1.79 +
    1.80 +  return NS_OK;
    1.81 +}
    1.82 +
    1.83 +/*
    1.84 + * Add a notation to draw, if the argument is the name of a known notation.
    1.85 + * @param aNotation string name of a notation
    1.86 + */
    1.87 +nsresult nsMathMLmencloseFrame::AddNotation(const nsAString& aNotation)
    1.88 +{
    1.89 +  nsresult rv;
    1.90 +
    1.91 +  if (aNotation.EqualsLiteral("longdiv")) {
    1.92 +    rv = AllocateMathMLChar(NOTATION_LONGDIV);
    1.93 +    NS_ENSURE_SUCCESS(rv, rv);
    1.94 +    mNotationsToDraw |= NOTATION_LONGDIV;
    1.95 +  } else if (aNotation.EqualsLiteral("actuarial")) {
    1.96 +    mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_TOP);
    1.97 +  } else if (aNotation.EqualsLiteral("radical")) {
    1.98 +    rv = AllocateMathMLChar(NOTATION_RADICAL);
    1.99 +    NS_ENSURE_SUCCESS(rv, rv);
   1.100 +    mNotationsToDraw |= NOTATION_RADICAL;
   1.101 +  } else if (aNotation.EqualsLiteral("box")) {
   1.102 +    mNotationsToDraw |= (NOTATION_LEFT | NOTATION_RIGHT |
   1.103 +                         NOTATION_TOP | NOTATION_BOTTOM);
   1.104 +  } else if (aNotation.EqualsLiteral("roundedbox")) {
   1.105 +    mNotationsToDraw |= NOTATION_ROUNDEDBOX;
   1.106 +  } else if (aNotation.EqualsLiteral("circle")) {
   1.107 +    mNotationsToDraw |= NOTATION_CIRCLE;
   1.108 +  } else if (aNotation.EqualsLiteral("left")) {
   1.109 +    mNotationsToDraw |= NOTATION_LEFT;
   1.110 +  } else if (aNotation.EqualsLiteral("right")) {
   1.111 +    mNotationsToDraw |= NOTATION_RIGHT;
   1.112 +  } else if (aNotation.EqualsLiteral("top")) {
   1.113 +    mNotationsToDraw |= NOTATION_TOP;
   1.114 +  } else if (aNotation.EqualsLiteral("bottom")) {
   1.115 +    mNotationsToDraw |= NOTATION_BOTTOM;
   1.116 +  } else if (aNotation.EqualsLiteral("updiagonalstrike")) {
   1.117 +    mNotationsToDraw |= NOTATION_UPDIAGONALSTRIKE;
   1.118 +  } else if (aNotation.EqualsLiteral("updiagonalarrow")) {
   1.119 +    mNotationsToDraw |= NOTATION_UPDIAGONALARROW;
   1.120 +  } else if (aNotation.EqualsLiteral("downdiagonalstrike")) {
   1.121 +    mNotationsToDraw |= NOTATION_DOWNDIAGONALSTRIKE;
   1.122 +  } else if (aNotation.EqualsLiteral("verticalstrike")) {
   1.123 +    mNotationsToDraw |= NOTATION_VERTICALSTRIKE;
   1.124 +  } else if (aNotation.EqualsLiteral("horizontalstrike")) {
   1.125 +    mNotationsToDraw |= NOTATION_HORIZONTALSTRIKE;
   1.126 +  } else if (aNotation.EqualsLiteral("madruwb")) {
   1.127 +    mNotationsToDraw |= (NOTATION_RIGHT | NOTATION_BOTTOM);
   1.128 +  }
   1.129 +
   1.130 +  return NS_OK;
   1.131 +}
   1.132 +
   1.133 +/*
   1.134 + * Initialize the list of notations to draw
   1.135 + */
   1.136 +void nsMathMLmencloseFrame::InitNotations()
   1.137 +{
   1.138 +  mNotationsToDraw = 0;
   1.139 +  mLongDivCharIndex = mRadicalCharIndex = -1;
   1.140 +  mMathMLChar.Clear();
   1.141 +
   1.142 +  nsAutoString value;
   1.143 +
   1.144 +  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::notation_, value)) {
   1.145 +    // parse the notation attribute
   1.146 +    nsWhitespaceTokenizer tokenizer(value);
   1.147 +
   1.148 +    while (tokenizer.hasMoreTokens())
   1.149 +      AddNotation(tokenizer.nextToken());
   1.150 +
   1.151 +    if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
   1.152 +      // For <menclose notation="updiagonalstrike updiagonalarrow">, if
   1.153 +      // the two notations are drawn then the strike line may cause the point of
   1.154 +      // the arrow to be too wide. Hence we will only draw the updiagonalarrow
   1.155 +      // and the arrow shaft may be thought to be the updiagonalstrike.
   1.156 +      mNotationsToDraw &= ~NOTATION_UPDIAGONALSTRIKE;
   1.157 +    }
   1.158 +  } else {
   1.159 +    // default: longdiv
   1.160 +    if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV)))
   1.161 +      return;
   1.162 +    mNotationsToDraw = NOTATION_LONGDIV;
   1.163 +  }
   1.164 +}
   1.165 +
   1.166 +NS_IMETHODIMP
   1.167 +nsMathMLmencloseFrame::InheritAutomaticData(nsIFrame* aParent)
   1.168 +{
   1.169 +  // let the base class get the default from our parent
   1.170 +  nsMathMLContainerFrame::InheritAutomaticData(aParent);
   1.171 +
   1.172 +  mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
   1.173 +
   1.174 +  InitNotations();
   1.175 +
   1.176 +  return NS_OK;
   1.177 +}
   1.178 +
   1.179 +NS_IMETHODIMP
   1.180 +nsMathMLmencloseFrame::TransmitAutomaticData()
   1.181 +{
   1.182 +  if (IsToDraw(NOTATION_RADICAL)) {
   1.183 +    // The TeXBook (Ch 17. p.141) says that \sqrt is cramped 
   1.184 +    UpdatePresentationDataFromChildAt(0, -1,
   1.185 +                                      NS_MATHML_COMPRESSED,
   1.186 +                                      NS_MATHML_COMPRESSED);
   1.187 +  }
   1.188 +
   1.189 +  return NS_OK;
   1.190 +}
   1.191 +
   1.192 +void
   1.193 +nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.194 +                                        const nsRect&           aDirtyRect,
   1.195 +                                        const nsDisplayListSet& aLists)
   1.196 +{
   1.197 +  /////////////
   1.198 +  // paint the menclosed content
   1.199 +  nsMathMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
   1.200 +
   1.201 +  if (NS_MATHML_HAS_ERROR(mPresentationData.flags))
   1.202 +    return;
   1.203 +
   1.204 +  nsRect mencloseRect = nsIFrame::GetRect();
   1.205 +  mencloseRect.x = mencloseRect.y = 0;
   1.206 +
   1.207 +  if (IsToDraw(NOTATION_RADICAL)) {
   1.208 +    mMathMLChar[mRadicalCharIndex].Display(aBuilder, this, aLists, 0);
   1.209 +
   1.210 +    nsRect rect;
   1.211 +    mMathMLChar[mRadicalCharIndex].GetRect(rect);
   1.212 +    rect.MoveBy(StyleVisibility()->mDirection ? -mContentWidth : rect.width, 0);
   1.213 +    rect.SizeTo(mContentWidth, mRuleThickness);
   1.214 +    DisplayBar(aBuilder, this, rect, aLists);
   1.215 +  }
   1.216 +
   1.217 +  if (IsToDraw(NOTATION_LONGDIV)) {
   1.218 +    mMathMLChar[mLongDivCharIndex].Display(aBuilder, this, aLists, 1);
   1.219 +
   1.220 +    nsRect rect;
   1.221 +    mMathMLChar[mLongDivCharIndex].GetRect(rect);
   1.222 +    rect.SizeTo(rect.width + mContentWidth, mRuleThickness);
   1.223 +    DisplayBar(aBuilder, this, rect, aLists);
   1.224 +  }
   1.225 +
   1.226 +  if (IsToDraw(NOTATION_TOP)) {
   1.227 +    nsRect rect(0, 0, mencloseRect.width, mRuleThickness);
   1.228 +    DisplayBar(aBuilder, this, rect, aLists);
   1.229 +  }
   1.230 +
   1.231 +  if (IsToDraw(NOTATION_BOTTOM)) {
   1.232 +    nsRect rect(0, mencloseRect.height - mRuleThickness,
   1.233 +                mencloseRect.width, mRuleThickness);
   1.234 +    DisplayBar(aBuilder, this, rect, aLists);
   1.235 +  }
   1.236 +
   1.237 +  if (IsToDraw(NOTATION_LEFT)) {
   1.238 +    nsRect rect(0, 0, mRuleThickness, mencloseRect.height);
   1.239 +    DisplayBar(aBuilder, this, rect, aLists);
   1.240 +  }
   1.241 +
   1.242 +  if (IsToDraw(NOTATION_RIGHT)) {
   1.243 +    nsRect rect(mencloseRect.width - mRuleThickness, 0,
   1.244 +                mRuleThickness, mencloseRect.height);
   1.245 +    DisplayBar(aBuilder, this, rect, aLists);
   1.246 +  }
   1.247 +
   1.248 +  if (IsToDraw(NOTATION_ROUNDEDBOX)) {
   1.249 +    DisplayNotation(aBuilder, this, mencloseRect, aLists,
   1.250 +                    mRuleThickness, NOTATION_ROUNDEDBOX);
   1.251 +  }
   1.252 +
   1.253 +  if (IsToDraw(NOTATION_CIRCLE)) {
   1.254 +    DisplayNotation(aBuilder, this, mencloseRect, aLists,
   1.255 +                    mRuleThickness, NOTATION_CIRCLE);
   1.256 +  }
   1.257 +
   1.258 +  if (IsToDraw(NOTATION_UPDIAGONALSTRIKE)) {
   1.259 +    DisplayNotation(aBuilder, this, mencloseRect, aLists,
   1.260 +                    mRuleThickness, NOTATION_UPDIAGONALSTRIKE);
   1.261 +  }
   1.262 +
   1.263 +  if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
   1.264 +    DisplayNotation(aBuilder, this, mencloseRect, aLists,
   1.265 +                    mRuleThickness, NOTATION_UPDIAGONALARROW);
   1.266 +  }
   1.267 +
   1.268 +  if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE)) {
   1.269 +    DisplayNotation(aBuilder, this, mencloseRect, aLists,
   1.270 +                    mRuleThickness, NOTATION_DOWNDIAGONALSTRIKE);
   1.271 +  }
   1.272 +
   1.273 +  if (IsToDraw(NOTATION_HORIZONTALSTRIKE)) {
   1.274 +    nsRect rect(0, mencloseRect.height / 2 - mRuleThickness / 2,
   1.275 +                mencloseRect.width, mRuleThickness);
   1.276 +    DisplayBar(aBuilder, this, rect, aLists);
   1.277 +  }
   1.278 +
   1.279 +  if (IsToDraw(NOTATION_VERTICALSTRIKE)) {
   1.280 +    nsRect rect(mencloseRect.width / 2 - mRuleThickness / 2, 0,
   1.281 +                mRuleThickness, mencloseRect.height);
   1.282 +    DisplayBar(aBuilder, this, rect, aLists);
   1.283 +  }
   1.284 +}
   1.285 +
   1.286 +/* virtual */ nsresult
   1.287 +nsMathMLmencloseFrame::MeasureForWidth(nsRenderingContext& aRenderingContext,
   1.288 +                                       nsHTMLReflowMetrics& aDesiredSize)
   1.289 +{
   1.290 +  return PlaceInternal(aRenderingContext, false, aDesiredSize, true);
   1.291 +}
   1.292 +
   1.293 +/* virtual */ nsresult
   1.294 +nsMathMLmencloseFrame::Place(nsRenderingContext& aRenderingContext,
   1.295 +                             bool                 aPlaceOrigin,
   1.296 +                             nsHTMLReflowMetrics& aDesiredSize)
   1.297 +{
   1.298 +  return PlaceInternal(aRenderingContext, aPlaceOrigin, aDesiredSize, false);
   1.299 +}
   1.300 +
   1.301 +/* virtual */ nsresult
   1.302 +nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
   1.303 +                                     bool                 aPlaceOrigin,
   1.304 +                                     nsHTMLReflowMetrics& aDesiredSize,
   1.305 +                                     bool                 aWidthOnly)
   1.306 +{
   1.307 +  ///////////////
   1.308 +  // Measure the size of our content using the base class to format like an
   1.309 +  // inferred mrow.
   1.310 +  nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode());
   1.311 +  nsresult rv =
   1.312 +    nsMathMLContainerFrame::Place(aRenderingContext, false, baseSize);
   1.313 +
   1.314 +  if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
   1.315 +      DidReflowChildren(GetFirstPrincipalChild());
   1.316 +      return rv;
   1.317 +    }
   1.318 +
   1.319 +  nsBoundingMetrics bmBase = baseSize.mBoundingMetrics;
   1.320 +  nscoord dx_left = 0, dx_right = 0;
   1.321 +  nsBoundingMetrics bmLongdivChar, bmRadicalChar;
   1.322 +  nscoord radicalAscent = 0, radicalDescent = 0;
   1.323 +  nscoord longdivAscent = 0, longdivDescent = 0;
   1.324 +  nscoord psi = 0;
   1.325 +
   1.326 +  ///////////////
   1.327 +  // Thickness of bars and font metrics
   1.328 +  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   1.329 +
   1.330 +  nscoord mEmHeight;
   1.331 +  nsRefPtr<nsFontMetrics> fm;
   1.332 +  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   1.333 +  aRenderingContext.SetFont(fm);
   1.334 +  GetRuleThickness(aRenderingContext, fm, mRuleThickness);
   1.335 +  GetEmHeight(fm, mEmHeight);
   1.336 +
   1.337 +  char16_t one = '1';
   1.338 +  nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1);
   1.339 +
   1.340 +  ///////////////
   1.341 +  // General rules: the menclose element takes the size of the enclosed content.
   1.342 +  // We add a padding when needed.
   1.343 +
   1.344 +  // determine padding & psi
   1.345 +  nscoord padding = 3 * mRuleThickness;
   1.346 +  nscoord delta = padding % onePixel;
   1.347 +  if (delta)
   1.348 +    padding += onePixel - delta; // round up
   1.349 +
   1.350 +  if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
   1.351 +      nscoord phi;
   1.352 +      // Rule 11, App. G, TeXbook
   1.353 +      // psi = clearance between rule and content
   1.354 +      if (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK)
   1.355 +        phi = fm->XHeight();
   1.356 +      else
   1.357 +        phi = mRuleThickness;
   1.358 +      psi = mRuleThickness + phi / 4;
   1.359 +
   1.360 +      delta = psi % onePixel;
   1.361 +      if (delta)
   1.362 +        psi += onePixel - delta; // round up
   1.363 +    }
   1.364 +
   1.365 +  if (mRuleThickness < onePixel)
   1.366 +    mRuleThickness = onePixel;
   1.367 + 
   1.368 +  // Set horizontal parameters
   1.369 +  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.370 +      IsToDraw(NOTATION_TOP) ||
   1.371 +      IsToDraw(NOTATION_LEFT) ||
   1.372 +      IsToDraw(NOTATION_BOTTOM) ||
   1.373 +      IsToDraw(NOTATION_CIRCLE))
   1.374 +    dx_left = padding;
   1.375 +
   1.376 +  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.377 +      IsToDraw(NOTATION_TOP) ||
   1.378 +      IsToDraw(NOTATION_RIGHT) ||
   1.379 +      IsToDraw(NOTATION_BOTTOM) ||
   1.380 +      IsToDraw(NOTATION_CIRCLE))
   1.381 +    dx_right = padding;
   1.382 +
   1.383 +  // Set vertical parameters
   1.384 +  if (IsToDraw(NOTATION_RIGHT) ||
   1.385 +      IsToDraw(NOTATION_LEFT) ||
   1.386 +      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
   1.387 +      IsToDraw(NOTATION_UPDIAGONALARROW) ||
   1.388 +      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
   1.389 +      IsToDraw(NOTATION_VERTICALSTRIKE) ||
   1.390 +      IsToDraw(NOTATION_CIRCLE) ||
   1.391 +      IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.392 +      IsToDraw(NOTATION_RADICAL) ||
   1.393 +      IsToDraw(NOTATION_LONGDIV)) {
   1.394 +      // set a minimal value for the base height
   1.395 +      bmBase.ascent = std::max(bmOne.ascent, bmBase.ascent);
   1.396 +      bmBase.descent = std::max(0, bmBase.descent);
   1.397 +  }
   1.398 +
   1.399 +  mBoundingMetrics.ascent = bmBase.ascent;
   1.400 +  mBoundingMetrics.descent = bmBase.descent;
   1.401 +    
   1.402 +  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.403 +      IsToDraw(NOTATION_TOP) ||
   1.404 +      IsToDraw(NOTATION_LEFT) ||
   1.405 +      IsToDraw(NOTATION_RIGHT) ||
   1.406 +      IsToDraw(NOTATION_CIRCLE))
   1.407 +    mBoundingMetrics.ascent += padding;
   1.408 +  
   1.409 +  if (IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.410 +      IsToDraw(NOTATION_LEFT) ||
   1.411 +      IsToDraw(NOTATION_RIGHT) ||
   1.412 +      IsToDraw(NOTATION_BOTTOM) ||
   1.413 +      IsToDraw(NOTATION_CIRCLE))
   1.414 +    mBoundingMetrics.descent += padding;
   1.415 +
   1.416 +  ///////////////
   1.417 +  // updiagonal arrow notation. We need enough space at the top right corner to
   1.418 +  // draw the arrow head.
   1.419 +  if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
   1.420 +    // This is an estimate, see nsDisplayNotation::Paint for the exact head size
   1.421 +    nscoord arrowHeadSize = kArrowHeadSize * mRuleThickness;
   1.422 +
   1.423 +    // We want that the arrow shaft strikes the menclose content and that the
   1.424 +    // arrow head does not overlap with that content. Hence we add some space
   1.425 +    // on the right. We don't add space on the top but only ensure that the
   1.426 +    // ascent is large enough.
   1.427 +    dx_right = std::max(dx_right, arrowHeadSize);
   1.428 +    mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, arrowHeadSize);
   1.429 +  }
   1.430 +
   1.431 +  ///////////////
   1.432 +  // circle notation: we don't want the ellipse to overlap the enclosed
   1.433 +  // content. Hence, we need to increase the size of the bounding box by a
   1.434 +  // factor of at least sqrt(2).
   1.435 +  if (IsToDraw(NOTATION_CIRCLE)) {
   1.436 +    double ratio = (sqrt(2.0) - 1.0) / 2.0;
   1.437 +    nscoord padding2;
   1.438 +
   1.439 +    // Update horizontal parameters
   1.440 +    padding2 = ratio * bmBase.width;
   1.441 +
   1.442 +    dx_left = std::max(dx_left, padding2);
   1.443 +    dx_right = std::max(dx_right, padding2);
   1.444 +
   1.445 +    // Update vertical parameters
   1.446 +    padding2 = ratio * (bmBase.ascent + bmBase.descent);
   1.447 +
   1.448 +    mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
   1.449 +                                     bmBase.ascent + padding2);
   1.450 +    mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
   1.451 +                                      bmBase.descent + padding2);
   1.452 +  }
   1.453 +
   1.454 +  ///////////////
   1.455 +  // longdiv notation:
   1.456 +  if (IsToDraw(NOTATION_LONGDIV)) {
   1.457 +    if (aWidthOnly) {
   1.458 +        nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].
   1.459 +          GetMaxWidth(PresContext(), aRenderingContext);
   1.460 +
   1.461 +        // Update horizontal parameters
   1.462 +        dx_left = std::max(dx_left, longdiv_width);
   1.463 +    } else {
   1.464 +      // Stretch the parenthesis to the appropriate height if it is not
   1.465 +      // big enough.
   1.466 +      nsBoundingMetrics contSize = bmBase;
   1.467 +      contSize.ascent = mRuleThickness;
   1.468 +      contSize.descent = bmBase.ascent + bmBase.descent + psi;
   1.469 +
   1.470 +      // height(longdiv) should be >= height(base) + psi + mRuleThickness
   1.471 +      mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aRenderingContext,
   1.472 +                                             NS_STRETCH_DIRECTION_VERTICAL,
   1.473 +                                             contSize, bmLongdivChar,
   1.474 +                                             NS_STRETCH_LARGER, false);
   1.475 +      mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar);
   1.476 +
   1.477 +      // Update horizontal parameters
   1.478 +      dx_left = std::max(dx_left, bmLongdivChar.width);
   1.479 +
   1.480 +      // Update vertical parameters
   1.481 +      longdivAscent = bmBase.ascent + psi + mRuleThickness;
   1.482 +      longdivDescent = std::max(bmBase.descent,
   1.483 +                              (bmLongdivChar.ascent + bmLongdivChar.descent -
   1.484 +                               longdivAscent));
   1.485 +
   1.486 +      mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
   1.487 +                                       longdivAscent);
   1.488 +      mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
   1.489 +                                        longdivDescent);
   1.490 +    }
   1.491 +  }
   1.492 +
   1.493 +  ///////////////
   1.494 +  // radical notation:
   1.495 +  if (IsToDraw(NOTATION_RADICAL)) {
   1.496 +    nscoord *dx_leading = StyleVisibility()->mDirection ? &dx_right : &dx_left;
   1.497 +    
   1.498 +    if (aWidthOnly) {
   1.499 +      nscoord radical_width = mMathMLChar[mRadicalCharIndex].
   1.500 +        GetMaxWidth(PresContext(), aRenderingContext);
   1.501 +      
   1.502 +      // Update horizontal parameters
   1.503 +      *dx_leading = std::max(*dx_leading, radical_width);
   1.504 +    } else {
   1.505 +      // Stretch the radical symbol to the appropriate height if it is not
   1.506 +      // big enough.
   1.507 +      nsBoundingMetrics contSize = bmBase;
   1.508 +      contSize.ascent = mRuleThickness;
   1.509 +      contSize.descent = bmBase.ascent + bmBase.descent + psi;
   1.510 +
   1.511 +      // height(radical) should be >= height(base) + psi + mRuleThickness
   1.512 +      mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext,
   1.513 +                                             NS_STRETCH_DIRECTION_VERTICAL,
   1.514 +                                             contSize, bmRadicalChar,
   1.515 +                                             NS_STRETCH_LARGER,
   1.516 +                                             StyleVisibility()->mDirection);
   1.517 +      mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar);
   1.518 +
   1.519 +      // Update horizontal parameters
   1.520 +      *dx_leading = std::max(*dx_leading, bmRadicalChar.width);
   1.521 +
   1.522 +      // Update vertical parameters
   1.523 +      radicalAscent = bmBase.ascent + psi + mRuleThickness;
   1.524 +      radicalDescent = std::max(bmBase.descent,
   1.525 +                              (bmRadicalChar.ascent + bmRadicalChar.descent -
   1.526 +                               radicalAscent));
   1.527 +
   1.528 +      mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
   1.529 +                                       radicalAscent);
   1.530 +      mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
   1.531 +                                        radicalDescent);
   1.532 +    }
   1.533 +  }
   1.534 +
   1.535 +  ///////////////
   1.536 +  //
   1.537 +  if (IsToDraw(NOTATION_CIRCLE) ||
   1.538 +      IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.539 +      (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) {
   1.540 +    // center the menclose around the content (horizontally)
   1.541 +    dx_left = dx_right = std::max(dx_left, dx_right);
   1.542 +  }
   1.543 +
   1.544 +  ///////////////
   1.545 +  // The maximum size is now computed: set the remaining parameters
   1.546 +  mBoundingMetrics.width = dx_left + bmBase.width + dx_right;
   1.547 +
   1.548 +  mBoundingMetrics.leftBearing = std::min(0, dx_left + bmBase.leftBearing);
   1.549 +  mBoundingMetrics.rightBearing =
   1.550 +    std::max(mBoundingMetrics.width, dx_left + bmBase.rightBearing);
   1.551 +  
   1.552 +  aDesiredSize.Width() = mBoundingMetrics.width;
   1.553 +
   1.554 +  aDesiredSize.SetTopAscent(std::max(mBoundingMetrics.ascent, baseSize.TopAscent()));
   1.555 +  aDesiredSize.Height() = aDesiredSize.TopAscent() +
   1.556 +    std::max(mBoundingMetrics.descent, baseSize.Height() - baseSize.TopAscent());
   1.557 +
   1.558 +  if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
   1.559 +    // get the leading to be left at the top of the resulting frame
   1.560 +    // this seems more reliable than using fm->GetLeading() on suspicious
   1.561 +    // fonts
   1.562 +    nscoord leading = nscoord(0.2f * mEmHeight);
   1.563 +    nscoord desiredSizeAscent = aDesiredSize.TopAscent();
   1.564 +    nscoord desiredSizeDescent = aDesiredSize.Height() - aDesiredSize.TopAscent();
   1.565 +    
   1.566 +    if (IsToDraw(NOTATION_LONGDIV)) {
   1.567 +      desiredSizeAscent = std::max(desiredSizeAscent,
   1.568 +                                 longdivAscent + leading);
   1.569 +      desiredSizeDescent = std::max(desiredSizeDescent,
   1.570 +                                  longdivDescent + mRuleThickness);
   1.571 +    }
   1.572 +    
   1.573 +    if (IsToDraw(NOTATION_RADICAL)) {
   1.574 +      desiredSizeAscent = std::max(desiredSizeAscent,
   1.575 +                                 radicalAscent + leading);
   1.576 +      desiredSizeDescent = std::max(desiredSizeDescent,
   1.577 +                                  radicalDescent + mRuleThickness);
   1.578 +    }
   1.579 +
   1.580 +    aDesiredSize.SetTopAscent(desiredSizeAscent);
   1.581 +    aDesiredSize.Height() = desiredSizeAscent + desiredSizeDescent;
   1.582 +  }
   1.583 +    
   1.584 +  if (IsToDraw(NOTATION_CIRCLE) ||
   1.585 +      IsToDraw(NOTATION_ROUNDEDBOX) ||
   1.586 +      (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) {
   1.587 +    // center the menclose around the content (vertically)
   1.588 +    nscoord dy = std::max(aDesiredSize.TopAscent() - bmBase.ascent,
   1.589 +                        aDesiredSize.Height() - aDesiredSize.TopAscent() -
   1.590 +                        bmBase.descent);
   1.591 +
   1.592 +    aDesiredSize.SetTopAscent(bmBase.ascent + dy);
   1.593 +    aDesiredSize.Height() = aDesiredSize.TopAscent() + bmBase.descent + dy;
   1.594 +  }
   1.595 +
   1.596 +  // Update mBoundingMetrics ascent/descent
   1.597 +  if (IsToDraw(NOTATION_TOP) ||
   1.598 +      IsToDraw(NOTATION_RIGHT) ||
   1.599 +      IsToDraw(NOTATION_LEFT) ||
   1.600 +      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
   1.601 +      IsToDraw(NOTATION_UPDIAGONALARROW) ||
   1.602 +      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
   1.603 +      IsToDraw(NOTATION_VERTICALSTRIKE) ||
   1.604 +      IsToDraw(NOTATION_CIRCLE) ||
   1.605 +      IsToDraw(NOTATION_ROUNDEDBOX))
   1.606 +    mBoundingMetrics.ascent = aDesiredSize.TopAscent();
   1.607 +  
   1.608 +  if (IsToDraw(NOTATION_BOTTOM) ||
   1.609 +      IsToDraw(NOTATION_RIGHT) ||
   1.610 +      IsToDraw(NOTATION_LEFT) ||
   1.611 +      IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
   1.612 +      IsToDraw(NOTATION_UPDIAGONALARROW) ||
   1.613 +      IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
   1.614 +      IsToDraw(NOTATION_VERTICALSTRIKE) ||
   1.615 +      IsToDraw(NOTATION_CIRCLE) ||
   1.616 +      IsToDraw(NOTATION_ROUNDEDBOX))
   1.617 +    mBoundingMetrics.descent = aDesiredSize.Height() - aDesiredSize.TopAscent();
   1.618 +
   1.619 +  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
   1.620 +  
   1.621 +  mReference.x = 0;
   1.622 +  mReference.y = aDesiredSize.TopAscent();
   1.623 +
   1.624 +  if (aPlaceOrigin) {
   1.625 +    //////////////////
   1.626 +    // Set position and size of MathMLChars
   1.627 +    if (IsToDraw(NOTATION_LONGDIV))
   1.628 +      mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left -
   1.629 +                                                    bmLongdivChar.width,
   1.630 +                                                    aDesiredSize.TopAscent() -
   1.631 +                                                    longdivAscent,
   1.632 +                                                    bmLongdivChar.width,
   1.633 +                                                    bmLongdivChar.ascent +
   1.634 +                                                    bmLongdivChar.descent));
   1.635 +
   1.636 +    if (IsToDraw(NOTATION_RADICAL)) {
   1.637 +      nscoord dx = (StyleVisibility()->mDirection ?
   1.638 +                    dx_left + bmBase.width : dx_left - bmRadicalChar.width);
   1.639 +
   1.640 +      mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx,
   1.641 +                                                    aDesiredSize.TopAscent() -
   1.642 +                                                    radicalAscent,
   1.643 +                                                    bmRadicalChar.width,
   1.644 +                                                    bmRadicalChar.ascent +
   1.645 +                                                    bmRadicalChar.descent));
   1.646 +    }
   1.647 +
   1.648 +    mContentWidth = bmBase.width;
   1.649 +
   1.650 +    //////////////////
   1.651 +    // Finish reflowing child frames
   1.652 +    PositionRowChildFrames(dx_left, aDesiredSize.TopAscent());
   1.653 +  }
   1.654 +
   1.655 +  return NS_OK;
   1.656 +}
   1.657 +
   1.658 +nscoord
   1.659 +nsMathMLmencloseFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
   1.660 +{
   1.661 +  nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
   1.662 +  if (!gap)
   1.663 +    return 0;
   1.664 +
   1.665 +  // Move the MathML characters
   1.666 +  nsRect rect;
   1.667 +  for (uint32_t i = 0; i < mMathMLChar.Length(); i++) {
   1.668 +    mMathMLChar[i].GetRect(rect);
   1.669 +    rect.MoveBy(gap, 0);
   1.670 +    mMathMLChar[i].SetRect(rect);
   1.671 +  }
   1.672 +
   1.673 +  return gap;
   1.674 +}
   1.675 +
   1.676 +nsresult
   1.677 +nsMathMLmencloseFrame::AttributeChanged(int32_t         aNameSpaceID,
   1.678 +                                        nsIAtom*        aAttribute,
   1.679 +                                        int32_t         aModType)
   1.680 +{
   1.681 +  if (aAttribute == nsGkAtoms::notation_) {
   1.682 +    InitNotations();
   1.683 +  }
   1.684 +
   1.685 +  return nsMathMLContainerFrame::
   1.686 +    AttributeChanged(aNameSpaceID, aAttribute, aModType);
   1.687 +}
   1.688 +
   1.689 +//////////////////
   1.690 +// the Style System will use these to pass the proper style context to our
   1.691 +// MathMLChar
   1.692 +nsStyleContext*
   1.693 +nsMathMLmencloseFrame::GetAdditionalStyleContext(int32_t aIndex) const
   1.694 +{
   1.695 +  int32_t len = mMathMLChar.Length();
   1.696 +  if (aIndex >= 0 && aIndex < len)
   1.697 +    return mMathMLChar[aIndex].GetStyleContext();
   1.698 +  else
   1.699 +    return nullptr;
   1.700 +}
   1.701 +
   1.702 +void
   1.703 +nsMathMLmencloseFrame::SetAdditionalStyleContext(int32_t          aIndex, 
   1.704 +                                                 nsStyleContext*  aStyleContext)
   1.705 +{
   1.706 +  int32_t len = mMathMLChar.Length();
   1.707 +  if (aIndex >= 0 && aIndex < len)
   1.708 +    mMathMLChar[aIndex].SetStyleContext(aStyleContext);
   1.709 +}
   1.710 +
   1.711 +class nsDisplayNotation : public nsDisplayItem
   1.712 +{
   1.713 +public:
   1.714 +  nsDisplayNotation(nsDisplayListBuilder* aBuilder,
   1.715 +                    nsIFrame* aFrame, const nsRect& aRect,
   1.716 +                    nscoord aThickness, nsMencloseNotation aType)
   1.717 +    : nsDisplayItem(aBuilder, aFrame), mRect(aRect), 
   1.718 +      mThickness(aThickness), mType(aType) {
   1.719 +    MOZ_COUNT_CTOR(nsDisplayNotation);
   1.720 +  }
   1.721 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.722 +  virtual ~nsDisplayNotation() {
   1.723 +    MOZ_COUNT_DTOR(nsDisplayNotation);
   1.724 +  }
   1.725 +#endif
   1.726 +
   1.727 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.728 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.729 +  NS_DISPLAY_DECL_NAME("MathMLMencloseNotation", TYPE_MATHML_MENCLOSE_NOTATION)
   1.730 +
   1.731 +private:
   1.732 +  nsRect             mRect;
   1.733 +  nscoord            mThickness;
   1.734 +  nsMencloseNotation mType;
   1.735 +};
   1.736 +
   1.737 +void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
   1.738 +                              nsRenderingContext* aCtx)
   1.739 +{
   1.740 +  // get the gfxRect
   1.741 +  nsPresContext* presContext = mFrame->PresContext();
   1.742 +  gfxRect rect = presContext->AppUnitsToGfxUnits(mRect + ToReferenceFrame());
   1.743 +
   1.744 +  // paint the frame with the current text color
   1.745 +  aCtx->SetColor(mFrame->GetVisitedDependentColor(eCSSProperty_color));
   1.746 +
   1.747 +  // change line width to mThickness
   1.748 +  gfxContext *gfxCtx = aCtx->ThebesContext();
   1.749 +  gfxFloat e = presContext->AppUnitsToGfxUnits(mThickness);
   1.750 +  gfxCtx->Save();
   1.751 +  gfxCtx->SetLineWidth(e);
   1.752 +
   1.753 +  rect.Deflate(e / 2.0);
   1.754 +
   1.755 +  switch(mType)
   1.756 +    {
   1.757 +    case NOTATION_CIRCLE:
   1.758 +      gfxCtx->NewPath();
   1.759 +      gfxCtx->Ellipse(rect.Center(), rect.Size());
   1.760 +      gfxCtx->Stroke();
   1.761 +      break;
   1.762 +
   1.763 +    case NOTATION_ROUNDEDBOX:
   1.764 +      gfxCtx->NewPath();
   1.765 +      gfxCtx->RoundedRectangle(rect, gfxCornerSizes(3 * e), true);
   1.766 +      gfxCtx->Stroke();
   1.767 +      break;
   1.768 +
   1.769 +    case NOTATION_UPDIAGONALSTRIKE:
   1.770 +      gfxCtx->NewPath();
   1.771 +      gfxCtx->Line(rect.BottomLeft(), rect.TopRight());
   1.772 +      gfxCtx->Stroke();
   1.773 +      break;
   1.774 +
   1.775 +    case NOTATION_DOWNDIAGONALSTRIKE:
   1.776 +      gfxCtx->NewPath();
   1.777 +      gfxCtx->Line(rect.TopLeft(), rect.BottomRight());
   1.778 +      gfxCtx->Stroke();
   1.779 +      break;
   1.780 +
   1.781 +    case NOTATION_UPDIAGONALARROW: {
   1.782 +      // Compute some parameters to draw the updiagonalarrow. The values below
   1.783 +      // are taken from MathJax's HTML-CSS output.
   1.784 +      gfxFloat W = rect.Width(); gfxFloat H = rect.Height();
   1.785 +      gfxFloat l = sqrt(W*W + H*H);
   1.786 +      gfxFloat f = gfxFloat(kArrowHeadSize) * e / l;
   1.787 +      gfxFloat w = W * f; gfxFloat h = H * f;
   1.788 +
   1.789 +      // Draw the arrow shaft
   1.790 +      gfxCtx->NewPath();
   1.791 +      gfxCtx->Line(rect.BottomLeft(), rect.TopRight() + gfxPoint(-.7*w, .7*h));
   1.792 +      gfxCtx->Stroke();
   1.793 +
   1.794 +      // Draw the arrow head
   1.795 +      gfxCtx->NewPath();
   1.796 +      gfxPoint p[] = {
   1.797 +        rect.TopRight(),
   1.798 +        rect.TopRight() + gfxPoint(-w -.4*h, std::max(-e / 2.0, h - .4*w)),
   1.799 +        rect.TopRight() + gfxPoint(-.7*w, .7*h),
   1.800 +        rect.TopRight() + gfxPoint(std::min(e / 2.0, -w + .4*h), h + .4*w),
   1.801 +        rect.TopRight()
   1.802 +      };
   1.803 +      gfxCtx->Polygon(p, MOZ_ARRAY_LENGTH(p));
   1.804 +      gfxCtx->Fill();
   1.805 +    }
   1.806 +      break;
   1.807 +
   1.808 +    default:
   1.809 +      NS_NOTREACHED("This notation can not be drawn using nsDisplayNotation");
   1.810 +      break;
   1.811 +    }
   1.812 +
   1.813 +  gfxCtx->Restore();
   1.814 +}
   1.815 +
   1.816 +void
   1.817 +nsMathMLmencloseFrame::DisplayNotation(nsDisplayListBuilder* aBuilder,
   1.818 +                                       nsIFrame* aFrame, const nsRect& aRect,
   1.819 +                                       const nsDisplayListSet& aLists,
   1.820 +                                       nscoord aThickness,
   1.821 +                                       nsMencloseNotation aType)
   1.822 +{
   1.823 +  if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty() ||
   1.824 +      aThickness <= 0)
   1.825 +    return;
   1.826 +
   1.827 +  aLists.Content()->AppendNewToTop(new (aBuilder)
   1.828 +    nsDisplayNotation(aBuilder, aFrame, aRect, aThickness, aType));
   1.829 +}

mercurial