layout/mathml/nsMathMLFrame.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial