layout/mathml/nsMathMLFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsMathMLFrame.h"
     7 #include "nsNameSpaceManager.h"
     8 #include "nsMathMLChar.h"
     9 #include "nsCSSPseudoElements.h"
    10 #include "nsMathMLElement.h"
    12 // used to map attributes into CSS rules
    13 #include "nsStyleSet.h"
    14 #include "nsAutoPtr.h"
    15 #include "nsDisplayList.h"
    16 #include "nsRenderingContext.h"
    18 eMathMLFrameType
    19 nsMathMLFrame::GetMathMLFrameType()
    20 {
    21   // see if it is an embellished operator (mapped to 'Op' in TeX)
    22   if (mEmbellishData.coreFrame)
    23     return GetMathMLFrameTypeFor(mEmbellishData.coreFrame);
    25   // if it has a prescribed base, fetch the type from there
    26   if (mPresentationData.baseFrame)
    27     return GetMathMLFrameTypeFor(mPresentationData.baseFrame);
    29   // everything else is treated as ordinary (mapped to 'Ord' in TeX)
    30   return eMathMLFrameType_Ordinary;  
    31 }
    33 NS_IMETHODIMP
    34 nsMathMLFrame::InheritAutomaticData(nsIFrame* aParent) 
    35 {
    36   mEmbellishData.flags = 0;
    37   mEmbellishData.coreFrame = nullptr;
    38   mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
    39   mEmbellishData.leadingSpace = 0;
    40   mEmbellishData.trailingSpace = 0;
    42   mPresentationData.flags = 0;
    43   mPresentationData.baseFrame = nullptr;
    45   // by default, just inherit the display of our parent
    46   nsPresentationData parentData;
    47   GetPresentationDataFrom(aParent, parentData);
    49 #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
    50   mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS;
    51 #endif
    53   return NS_OK;
    54 }
    56 NS_IMETHODIMP
    57 nsMathMLFrame::UpdatePresentationData(uint32_t        aFlagsValues,
    58                                       uint32_t        aWhichFlags)
    59 {
    60   NS_ASSERTION(NS_MATHML_IS_COMPRESSED(aWhichFlags),
    61                "aWhichFlags should only be compression flag"); 
    63   if (NS_MATHML_IS_COMPRESSED(aWhichFlags)) {
    64     // updating the compression flag is allowed
    65     if (NS_MATHML_IS_COMPRESSED(aFlagsValues)) {
    66       // 'compressed' means 'prime' style in App. G, TeXbook
    67       mPresentationData.flags |= NS_MATHML_COMPRESSED;
    68     }
    69     // no else. the flag is sticky. it retains its value once it is set
    70   }
    71   return NS_OK;
    72 }
    74 // Helper to give a style context suitable for doing the stretching of
    75 // a MathMLChar. Frame classes that use this should ensure that the 
    76 // extra leaf style contexts given to the MathMLChars are accessible to
    77 // the Style System via the Get/Set AdditionalStyleContext() APIs.
    78 /* static */ void
    79 nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext*  aPresContext,
    80                                       nsIContent*      aContent,
    81                                       nsStyleContext*  aParentStyleContext,
    82                                       nsMathMLChar*    aMathMLChar)
    83 {
    84   nsCSSPseudoElements::Type pseudoType =
    85     nsCSSPseudoElements::ePseudo_mozMathAnonymous; // savings
    86   nsRefPtr<nsStyleContext> newStyleContext;
    87   newStyleContext = aPresContext->StyleSet()->
    88     ResolvePseudoElementStyle(aContent->AsElement(), pseudoType,
    89                               aParentStyleContext, nullptr);
    91   aMathMLChar->SetStyleContext(newStyleContext);
    92 }
    94 /* static */ void
    95 nsMathMLFrame::GetEmbellishDataFrom(nsIFrame*        aFrame,
    96                                     nsEmbellishData& aEmbellishData)
    97 {
    98   // initialize OUT params
    99   aEmbellishData.flags = 0;
   100   aEmbellishData.coreFrame = nullptr;
   101   aEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
   102   aEmbellishData.leadingSpace = 0;
   103   aEmbellishData.trailingSpace = 0;
   105   if (aFrame && aFrame->IsFrameOfType(nsIFrame::eMathML)) {
   106     nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
   107     if (mathMLFrame) {
   108       mathMLFrame->GetEmbellishData(aEmbellishData);
   109     }
   110   }
   111 }
   113 // helper to get the presentation data of a frame, by possibly walking up
   114 // the frame hierarchy if we happen to be surrounded by non-MathML frames.
   115 /* static */ void
   116 nsMathMLFrame::GetPresentationDataFrom(nsIFrame*           aFrame,
   117                                        nsPresentationData& aPresentationData,
   118                                        bool                aClimbTree)
   119 {
   120   // initialize OUT params
   121   aPresentationData.flags = 0;
   122   aPresentationData.baseFrame = nullptr;
   124   nsIFrame* frame = aFrame;
   125   while (frame) {
   126     if (frame->IsFrameOfType(nsIFrame::eMathML)) {
   127       nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame);
   128       if (mathMLFrame) {
   129         mathMLFrame->GetPresentationData(aPresentationData);
   130         break;
   131       }
   132     }
   133     // stop if the caller doesn't want to lookup beyond the frame
   134     if (!aClimbTree) {
   135       break;
   136     }
   137     // stop if we reach the root <math> tag
   138     nsIContent* content = frame->GetContent();
   139     NS_ASSERTION(content || !frame->GetParent(), // no assert for the root
   140                  "dangling frame without a content node"); 
   141     if (!content)
   142       break;
   144     if (content->Tag() == nsGkAtoms::math) {
   145       break;
   146     }
   147     frame = frame->GetParent();
   148   }
   149   NS_WARN_IF_FALSE(frame && frame->GetContent(),
   150                    "bad MathML markup - could not find the top <math> element");
   151 }
   153 /* static */ void
   154 nsMathMLFrame::GetRuleThickness(nsRenderingContext& aRenderingContext,
   155                                 nsFontMetrics*      aFontMetrics,
   156                                 nscoord&             aRuleThickness)
   157 {
   158   // get the bounding metrics of the overbar char, the rendering context
   159   // is assumed to have been set with the font of the current style context
   160   NS_ASSERTION(aRenderingContext.FontMetrics()->Font().
   161                Equals(aFontMetrics->Font()),
   162                "unexpected state");
   164   nscoord xHeight = aFontMetrics->XHeight();
   165   char16_t overBar = 0x00AF;
   166   nsBoundingMetrics bm = aRenderingContext.GetBoundingMetrics(&overBar, 1);
   167   aRuleThickness = bm.ascent + bm.descent;
   168   if (aRuleThickness <= 0 || aRuleThickness >= xHeight) {
   169     // fall-back to the other version
   170     GetRuleThickness(aFontMetrics, aRuleThickness);
   171   }
   172 }
   174 /* static */ void
   175 nsMathMLFrame::GetAxisHeight(nsRenderingContext& aRenderingContext,
   176                              nsFontMetrics*      aFontMetrics,
   177                              nscoord&             aAxisHeight)
   178 {
   179   // get the bounding metrics of the minus sign, the rendering context
   180   // is assumed to have been set with the font of the current style context
   181   NS_ASSERTION(aRenderingContext.FontMetrics()->Font().
   182                Equals(aFontMetrics->Font()),
   183                "unexpected state");
   185   nscoord xHeight = aFontMetrics->XHeight();
   186   char16_t minus = 0x2212; // not '-', but official Unicode minus sign
   187   nsBoundingMetrics bm = aRenderingContext.GetBoundingMetrics(&minus, 1);
   188   aAxisHeight = bm.ascent - (bm.ascent + bm.descent)/2;
   189   if (aAxisHeight <= 0 || aAxisHeight >= xHeight) {
   190     // fall-back to the other version
   191     GetAxisHeight(aFontMetrics, aAxisHeight);
   192   }
   193 }
   195 /* static */ nscoord
   196 nsMathMLFrame::CalcLength(nsPresContext*   aPresContext,
   197                           nsStyleContext*   aStyleContext,
   198                           const nsCSSValue& aCSSValue)
   199 {
   200   NS_ASSERTION(aCSSValue.IsLengthUnit(), "not a length unit");
   202   if (aCSSValue.IsFixedLengthUnit()) {
   203     return aCSSValue.GetFixedLength(aPresContext);
   204   }
   205   if (aCSSValue.IsPixelLengthUnit()) {
   206     return aCSSValue.GetPixelLength();
   207   }
   209   nsCSSUnit unit = aCSSValue.GetUnit();
   211   if (eCSSUnit_EM == unit) {
   212     const nsStyleFont* font = aStyleContext->StyleFont();
   213     return NSToCoordRound(aCSSValue.GetFloatValue() * (float)font->mFont.size);
   214   }
   215   else if (eCSSUnit_XHeight == unit) {
   216     nsRefPtr<nsFontMetrics> fm;
   217     nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext,
   218                                                  getter_AddRefs(fm));
   219     nscoord xHeight = fm->XHeight();
   220     return NSToCoordRound(aCSSValue.GetFloatValue() * (float)xHeight);
   221   }
   223   // MathML doesn't specify other CSS units such as rem or ch
   224   NS_ERROR("Unsupported unit");
   225   return 0;
   226 }
   228 /* static */ void
   229 nsMathMLFrame::ParseNumericValue(const nsString&   aString,
   230                                  nscoord*          aLengthValue,
   231                                  uint32_t          aFlags,
   232                                  nsPresContext*    aPresContext,
   233                                  nsStyleContext*   aStyleContext)
   234 {
   235   nsCSSValue cssValue;
   237   if (!nsMathMLElement::ParseNumericValue(aString, cssValue, aFlags,
   238                                           aPresContext->Document())) {
   239     // Invalid attribute value. aLengthValue remains unchanged, so the default
   240     // length value is used.
   241     return;
   242   }
   244   nsCSSUnit unit = cssValue.GetUnit();
   246   if (unit == eCSSUnit_Percent || unit == eCSSUnit_Number) {
   247     // Relative units. A multiple of the default length value is used.
   248     *aLengthValue = NSToCoordRound(*aLengthValue * (unit == eCSSUnit_Percent ?
   249                                                     cssValue.GetPercentValue() :
   250                                                     cssValue.GetFloatValue()));
   251     return;
   252   }
   254   // Absolute units.
   255   *aLengthValue = CalcLength(aPresContext, aStyleContext, cssValue);
   256 }
   258 // ================
   259 // Utils to map attributes into CSS rules (work-around to bug 69409 which
   260 // is not scheduled to be fixed anytime soon)
   261 //
   263 struct
   264 nsCSSMapping {
   265   int32_t        compatibility;
   266   const nsIAtom* attrAtom;
   267   const char*    cssProperty;
   268 };
   270 #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
   271 class nsDisplayMathMLBoundingMetrics : public nsDisplayItem {
   272 public:
   273   nsDisplayMathMLBoundingMetrics(nsDisplayListBuilder* aBuilder,
   274                                  nsIFrame* aFrame, const nsRect& aRect)
   275     : nsDisplayItem(aBuilder, aFrame), mRect(aRect) {
   276     MOZ_COUNT_CTOR(nsDisplayMathMLBoundingMetrics);
   277   }
   278 #ifdef NS_BUILD_REFCNT_LOGGING
   279   virtual ~nsDisplayMathMLBoundingMetrics() {
   280     MOZ_COUNT_DTOR(nsDisplayMathMLBoundingMetrics);
   281   }
   282 #endif
   284   virtual void Paint(nsDisplayListBuilder* aBuilder,
   285                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   286   NS_DISPLAY_DECL_NAME("MathMLBoundingMetrics", TYPE_MATHML_BOUNDING_METRICS)
   287 private:
   288   nsRect    mRect;
   289 };
   291 void nsDisplayMathMLBoundingMetrics::Paint(nsDisplayListBuilder* aBuilder,
   292                                            nsRenderingContext* aCtx)
   293 {
   294   aCtx->SetColor(NS_RGB(0,0,255));
   295   aCtx->DrawRect(mRect + ToReferenceFrame());
   296 }
   298 nsresult
   299 nsMathMLFrame::DisplayBoundingMetrics(nsDisplayListBuilder* aBuilder,
   300                                       nsIFrame* aFrame, const nsPoint& aPt,
   301                                       const nsBoundingMetrics& aMetrics,
   302                                       const nsDisplayListSet& aLists) {
   303   if (!NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags))
   304     return NS_OK;
   306   nscoord x = aPt.x + aMetrics.leftBearing;
   307   nscoord y = aPt.y - aMetrics.ascent;
   308   nscoord w = aMetrics.rightBearing - aMetrics.leftBearing;
   309   nscoord h = aMetrics.ascent + aMetrics.descent;
   311   return aLists.Content()->AppendNewToTop(new (aBuilder)
   312       nsDisplayMathMLBoundingMetrics(aBuilder, this, nsRect(x,y,w,h)));
   313 }
   314 #endif
   316 class nsDisplayMathMLBar : public nsDisplayItem {
   317 public:
   318   nsDisplayMathMLBar(nsDisplayListBuilder* aBuilder,
   319                      nsIFrame* aFrame, const nsRect& aRect)
   320     : nsDisplayItem(aBuilder, aFrame), mRect(aRect) {
   321     MOZ_COUNT_CTOR(nsDisplayMathMLBar);
   322   }
   323 #ifdef NS_BUILD_REFCNT_LOGGING
   324   virtual ~nsDisplayMathMLBar() {
   325     MOZ_COUNT_DTOR(nsDisplayMathMLBar);
   326   }
   327 #endif
   329   virtual void Paint(nsDisplayListBuilder* aBuilder,
   330                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   331   NS_DISPLAY_DECL_NAME("MathMLBar", TYPE_MATHML_BAR)
   332 private:
   333   nsRect    mRect;
   334 };
   336 void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder,
   337                                nsRenderingContext* aCtx)
   338 {
   339   // paint the bar with the current text color
   340   aCtx->SetColor(mFrame->GetVisitedDependentColor(eCSSProperty_color));
   341   aCtx->FillRect(mRect + ToReferenceFrame());
   342 }
   344 void
   345 nsMathMLFrame::DisplayBar(nsDisplayListBuilder* aBuilder,
   346                           nsIFrame* aFrame, const nsRect& aRect,
   347                           const nsDisplayListSet& aLists) {
   348   if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty())
   349     return;
   351   aLists.Content()->AppendNewToTop(new (aBuilder)
   352     nsDisplayMathMLBar(aBuilder, aFrame, aRect));
   353 }

mercurial