Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / mathml / base / src / nsMathMLFrame.cpp
blob6eeaea306e812d94af1010139b016f59fe057f88
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla MathML Project.
17 * The Initial Developer of the Original Code is
18 * The University Of Queensland.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Roger B. Sidje <rbs@maths.uq.edu.au>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsINameSpaceManager.h"
40 #include "nsMathMLFrame.h"
41 #include "nsMathMLChar.h"
42 #include "nsCSSAnonBoxes.h"
44 // used to map attributes into CSS rules
45 #include "nsIDocument.h"
46 #include "nsStyleSet.h"
47 #include "nsIStyleSheet.h"
48 #include "nsICSSStyleSheet.h"
49 #include "nsIDOMCSSStyleSheet.h"
50 #include "nsICSSRule.h"
51 #include "nsICSSStyleRule.h"
52 #include "nsStyleChangeList.h"
53 #include "nsFrameManager.h"
54 #include "nsNetUtil.h"
55 #include "nsIURI.h"
56 #include "nsContentCID.h"
57 #include "nsAutoPtr.h"
58 #include "nsStyleSet.h"
59 #include "nsStyleUtil.h"
60 #include "nsDisplayList.h"
61 #include "nsAttrName.h"
63 static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID);
66 NS_IMPL_QUERY_INTERFACE1(nsMathMLFrame, nsIMathMLFrame)
68 eMathMLFrameType
69 nsMathMLFrame::GetMathMLFrameType()
71 // see if it is an embellished operator (mapped to 'Op' in TeX)
72 if (mEmbellishData.coreFrame)
73 return GetMathMLFrameTypeFor(mEmbellishData.coreFrame);
75 // if it has a prescribed base, fetch the type from there
76 if (mPresentationData.baseFrame)
77 return GetMathMLFrameTypeFor(mPresentationData.baseFrame);
79 // everything else is treated as ordinary (mapped to 'Ord' in TeX)
80 return eMathMLFrameType_Ordinary;
83 // snippet of code used by <mstyle> and <mtable>, which are the only
84 // two tags where the displaystyle attribute is allowed by the spec.
85 /* static */ void
86 nsMathMLFrame::FindAttrDisplaystyle(nsIContent* aContent,
87 nsPresentationData& aPresentationData)
89 NS_ASSERTION(aContent->Tag() == nsGkAtoms::mstyle_ ||
90 aContent->Tag() == nsGkAtoms::mtable_, "bad caller");
91 static nsIContent::AttrValuesArray strings[] =
92 {&nsGkAtoms::_false, &nsGkAtoms::_true, nsnull};
93 // see if the explicit displaystyle attribute is there
94 switch (aContent->FindAttrValueIn(kNameSpaceID_None,
95 nsGkAtoms::displaystyle_, strings, eCaseMatters)) {
96 case 0:
97 aPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE;
98 aPresentationData.flags |= NS_MATHML_EXPLICIT_DISPLAYSTYLE;
99 break;
100 case 1:
101 aPresentationData.flags |= NS_MATHML_DISPLAYSTYLE;
102 aPresentationData.flags |= NS_MATHML_EXPLICIT_DISPLAYSTYLE;
103 break;
105 // no reset if the attr isn't found. so be sure to call it on inherited flags
108 NS_IMETHODIMP
109 nsMathMLFrame::InheritAutomaticData(nsIFrame* aParent)
111 mEmbellishData.flags = 0;
112 mEmbellishData.coreFrame = nsnull;
113 mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
114 mEmbellishData.leftSpace = 0;
115 mEmbellishData.rightSpace = 0;
117 mPresentationData.flags = 0;
118 mPresentationData.baseFrame = nsnull;
119 mPresentationData.mstyle = nsnull;
121 // by default, just inherit the display of our parent
122 nsPresentationData parentData;
123 GetPresentationDataFrom(aParent, parentData);
124 mPresentationData.mstyle = parentData.mstyle;
125 if (NS_MATHML_IS_DISPLAYSTYLE(parentData.flags)) {
126 mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE;
129 #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
130 mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS;
131 #endif
133 return NS_OK;
136 NS_IMETHODIMP
137 nsMathMLFrame::UpdatePresentationData(PRUint32 aFlagsValues,
138 PRUint32 aWhichFlags)
140 // update flags that are relevant to this call
141 if (NS_MATHML_IS_DISPLAYSTYLE(aWhichFlags)) {
142 // updating the displaystyle flag is allowed
143 if (NS_MATHML_IS_DISPLAYSTYLE(aFlagsValues)) {
144 mPresentationData.flags |= NS_MATHML_DISPLAYSTYLE;
146 else {
147 mPresentationData.flags &= ~NS_MATHML_DISPLAYSTYLE;
150 if (NS_MATHML_IS_COMPRESSED(aWhichFlags)) {
151 // updating the compression flag is allowed
152 if (NS_MATHML_IS_COMPRESSED(aFlagsValues)) {
153 // 'compressed' means 'prime' style in App. G, TeXbook
154 mPresentationData.flags |= NS_MATHML_COMPRESSED;
156 // no else. the flag is sticky. it retains its value once it is set
158 return NS_OK;
161 // Helper to give a style context suitable for doing the stretching of
162 // a MathMLChar. Frame classes that use this should ensure that the
163 // extra leaf style contexts given to the MathMLChars are accessible to
164 // the Style System via the Get/Set AdditionalStyleContext() APIs.
165 /* static */ void
166 nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext* aPresContext,
167 nsIContent* aContent,
168 nsStyleContext* aParentStyleContext,
169 nsMathMLChar* aMathMLChar,
170 PRBool aIsMutableChar)
172 nsIAtom* pseudoStyle = (aIsMutableChar) ?
173 nsCSSAnonBoxes::mozMathStretchy :
174 nsCSSAnonBoxes::mozMathAnonymous; // savings
175 nsRefPtr<nsStyleContext> newStyleContext;
176 newStyleContext = aPresContext->StyleSet()->
177 ResolvePseudoStyleFor(aContent, pseudoStyle, aParentStyleContext);
179 if (newStyleContext)
180 aMathMLChar->SetStyleContext(newStyleContext);
183 /* static */ void
184 nsMathMLFrame::GetEmbellishDataFrom(nsIFrame* aFrame,
185 nsEmbellishData& aEmbellishData)
187 // initialize OUT params
188 aEmbellishData.flags = 0;
189 aEmbellishData.coreFrame = nsnull;
190 aEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
191 aEmbellishData.leftSpace = 0;
192 aEmbellishData.rightSpace = 0;
194 if (aFrame && aFrame->IsFrameOfType(nsIFrame::eMathML)) {
195 nsIMathMLFrame* mathMLFrame;
196 CallQueryInterface(aFrame, &mathMLFrame);
197 if (mathMLFrame) {
198 mathMLFrame->GetEmbellishData(aEmbellishData);
203 // helper to get the presentation data of a frame, by possibly walking up
204 // the frame hierarchy if we happen to be surrounded by non-MathML frames.
205 /* static */ void
206 nsMathMLFrame::GetPresentationDataFrom(nsIFrame* aFrame,
207 nsPresentationData& aPresentationData,
208 PRBool aClimbTree)
210 // initialize OUT params
211 aPresentationData.flags = 0;
212 aPresentationData.baseFrame = nsnull;
213 aPresentationData.mstyle = nsnull;
215 nsIFrame* frame = aFrame;
216 while (frame) {
217 if (frame->IsFrameOfType(nsIFrame::eMathML)) {
218 nsIMathMLFrame* mathMLFrame;
219 CallQueryInterface(frame, &mathMLFrame);
220 if (mathMLFrame) {
221 mathMLFrame->GetPresentationData(aPresentationData);
222 break;
225 // stop if the caller doesn't want to lookup beyond the frame
226 if (!aClimbTree) {
227 break;
229 // stop if we reach the root <math> tag
230 nsIContent* content = frame->GetContent();
231 NS_ASSERTION(content || !frame->GetParent(), // no assert for the root
232 "dangling frame without a content node");
233 if (!content)
234 break;
236 if (content->Tag() == nsGkAtoms::math) {
237 const nsStyleDisplay* display = frame->GetStyleDisplay();
238 if (display->mDisplay == NS_STYLE_DISPLAY_BLOCK) {
239 aPresentationData.flags |= NS_MATHML_DISPLAYSTYLE;
241 break;
243 frame = frame->GetParent();
245 NS_WARN_IF_FALSE(frame && frame->GetContent(),
246 "bad MathML markup - could not find the top <math> element");
249 // helper to get an attribute from the content or the surrounding <mstyle> hierarchy
250 /* static */ PRBool
251 nsMathMLFrame::GetAttribute(nsIContent* aContent,
252 nsIFrame* aMathMLmstyleFrame,
253 nsIAtom* aAttributeAtom,
254 nsString& aValue)
256 // see if we can get the attribute from the content
257 if (aContent && aContent->GetAttr(kNameSpaceID_None, aAttributeAtom,
258 aValue)) {
259 return PR_TRUE;
262 // see if we can get the attribute from the mstyle frame
263 if (!aMathMLmstyleFrame) {
264 return PR_FALSE;
267 nsIFrame* mstyleParent = aMathMLmstyleFrame->GetParent();
269 nsPresentationData mstyleParentData;
270 mstyleParentData.mstyle = nsnull;
272 if (mstyleParent) {
273 nsIMathMLFrame* mathMLFrame;
274 CallQueryInterface(mstyleParent, &mathMLFrame);
275 if (mathMLFrame) {
276 mathMLFrame->GetPresentationData(mstyleParentData);
280 // recurse all the way up into the <mstyle> hierarchy
281 return GetAttribute(aMathMLmstyleFrame->GetContent(),
282 mstyleParentData.mstyle, aAttributeAtom, aValue);
285 /* static */ void
286 nsMathMLFrame::GetRuleThickness(nsIRenderingContext& aRenderingContext,
287 nsIFontMetrics* aFontMetrics,
288 nscoord& aRuleThickness)
290 // get the bounding metrics of the overbar char, the rendering context
291 // is assumed to have been set with the font of the current style context
292 #ifdef NS_DEBUG
293 nsCOMPtr<nsIFontMetrics> currFontMetrics;
294 aRenderingContext.GetFontMetrics(*getter_AddRefs(currFontMetrics));
295 NS_ASSERTION(currFontMetrics->Font().Equals(aFontMetrics->Font()),
296 "unexpected state");
297 #endif
298 nscoord xHeight;
299 aFontMetrics->GetXHeight(xHeight);
300 PRUnichar overBar = 0x00AF;
301 nsBoundingMetrics bm;
302 nsresult rv = aRenderingContext.GetBoundingMetrics(&overBar, PRUint32(1), bm);
303 if (NS_SUCCEEDED(rv)) {
304 aRuleThickness = bm.ascent + bm.descent;
306 if (NS_FAILED(rv) || aRuleThickness <= 0 || aRuleThickness >= xHeight) {
307 // fall-back to the other version
308 GetRuleThickness(aFontMetrics, aRuleThickness);
311 #if 0
312 nscoord oldRuleThickness;
313 GetRuleThickness(aFontMetrics, oldRuleThickness);
315 PRUnichar sqrt = 0xE063; // a sqrt glyph from TeX's CMEX font
316 rv = aRenderingContext.GetBoundingMetrics(&sqrt, PRUint32(1), bm);
317 nscoord sqrtrule = bm.ascent; // according to TeX, the ascent should be the rule
319 printf("xheight:%4d rule:%4d oldrule:%4d sqrtrule:%4d\n",
320 xHeight, aRuleThickness, oldRuleThickness, sqrtrule);
321 #endif
324 /* static */ void
325 nsMathMLFrame::GetAxisHeight(nsIRenderingContext& aRenderingContext,
326 nsIFontMetrics* aFontMetrics,
327 nscoord& aAxisHeight)
329 // get the bounding metrics of the minus sign, the rendering context
330 // is assumed to have been set with the font of the current style context
331 #ifdef NS_DEBUG
332 nsCOMPtr<nsIFontMetrics> currFontMetrics;
333 aRenderingContext.GetFontMetrics(*getter_AddRefs(currFontMetrics));
334 NS_ASSERTION(currFontMetrics->Font().Equals(aFontMetrics->Font()),
335 "unexpected state");
336 #endif
337 nscoord xHeight;
338 aFontMetrics->GetXHeight(xHeight);
339 PRUnichar minus = 0x2212; // not '-', but official Unicode minus sign
340 nsBoundingMetrics bm;
341 nsresult rv = aRenderingContext.GetBoundingMetrics(&minus, PRUint32(1), bm);
342 if (NS_SUCCEEDED(rv)) {
343 aAxisHeight = bm.ascent - (bm.ascent + bm.descent)/2;
345 if (NS_FAILED(rv) || aAxisHeight <= 0 || aAxisHeight >= xHeight) {
346 // fall-back to the other version
347 GetAxisHeight(aFontMetrics, aAxisHeight);
351 /* static */ nscoord
352 nsMathMLFrame::CalcLength(nsPresContext* aPresContext,
353 nsStyleContext* aStyleContext,
354 const nsCSSValue& aCSSValue)
356 NS_ASSERTION(aCSSValue.IsLengthUnit(), "not a length unit");
358 if (aCSSValue.IsFixedLengthUnit()) {
359 return aPresContext->TwipsToAppUnits(aCSSValue.GetLengthTwips());
362 nsCSSUnit unit = aCSSValue.GetUnit();
364 if (eCSSUnit_Pixel == unit) {
365 return nsPresContext::CSSPixelsToAppUnits(aCSSValue.GetFloatValue());
367 else if (eCSSUnit_EM == unit) {
368 const nsStyleFont* font = aStyleContext->GetStyleFont();
369 return NSToCoordRound(aCSSValue.GetFloatValue() * (float)font->mFont.size);
371 else if (eCSSUnit_XHeight == unit) {
372 nscoord xHeight;
373 const nsStyleFont* font = aStyleContext->GetStyleFont();
374 nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font->mFont);
375 fm->GetXHeight(xHeight);
376 return NSToCoordRound(aCSSValue.GetFloatValue() * (float)xHeight);
379 return 0;
382 /* static */ PRBool
383 nsMathMLFrame::ParseNamedSpaceValue(nsIFrame* aMathMLmstyleFrame,
384 nsString& aString,
385 nsCSSValue& aCSSValue)
387 aCSSValue.Reset();
388 aString.CompressWhitespace(); // aString is not a const in this code...
389 if (!aString.Length()) return PR_FALSE;
391 // See if it is one of the 'namedspace' (ranging 1/18em...7/18em)
392 PRInt32 i = 0;
393 nsIAtom* namedspaceAtom = nsnull;
394 if (aString.EqualsLiteral("veryverythinmathspace")) {
395 i = 1;
396 namedspaceAtom = nsGkAtoms::veryverythinmathspace_;
398 else if (aString.EqualsLiteral("verythinmathspace")) {
399 i = 2;
400 namedspaceAtom = nsGkAtoms::verythinmathspace_;
402 else if (aString.EqualsLiteral("thinmathspace")) {
403 i = 3;
404 namedspaceAtom = nsGkAtoms::thinmathspace_;
406 else if (aString.EqualsLiteral("mediummathspace")) {
407 i = 4;
408 namedspaceAtom = nsGkAtoms::mediummathspace_;
410 else if (aString.EqualsLiteral("thickmathspace")) {
411 i = 5;
412 namedspaceAtom = nsGkAtoms::thickmathspace_;
414 else if (aString.EqualsLiteral("verythickmathspace")) {
415 i = 6;
416 namedspaceAtom = nsGkAtoms::verythickmathspace_;
418 else if (aString.EqualsLiteral("veryverythickmathspace")) {
419 i = 7;
420 namedspaceAtom = nsGkAtoms::veryverythickmathspace_;
423 if (0 != i) {
424 if (aMathMLmstyleFrame) {
425 // see if there is a <mstyle> that has overriden the default value
426 // GetAttribute() will recurse all the way up into the <mstyle> hierarchy
427 nsAutoString value;
428 GetAttribute(nsnull, aMathMLmstyleFrame, namedspaceAtom, value);
429 if (!value.IsEmpty()) {
430 if (ParseNumericValue(value, aCSSValue) &&
431 aCSSValue.IsLengthUnit()) {
432 return PR_TRUE;
437 // fall back to the default value
438 aCSSValue.SetFloatValue(float(i)/float(18), eCSSUnit_EM);
439 return PR_TRUE;
442 return PR_FALSE;
445 // ================
446 // Utils to map attributes into CSS rules (work-around to bug 69409 which
447 // is not scheduled to be fixed anytime soon)
450 static const PRInt32 kMathMLversion1 = 1;
451 static const PRInt32 kMathMLversion2 = 2;
453 struct
454 nsCSSMapping {
455 PRInt32 compatibility;
456 const nsIAtom* attrAtom;
457 const char* cssProperty;
460 #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
461 class nsDisplayMathMLBoundingMetrics : public nsDisplayItem {
462 public:
463 nsDisplayMathMLBoundingMetrics(nsIFrame* aFrame, const nsRect& aRect)
464 : nsDisplayItem(aFrame), mRect(aRect) {
465 MOZ_COUNT_CTOR(nsDisplayMathMLBoundingMetrics);
467 #ifdef NS_BUILD_REFCNT_LOGGING
468 virtual ~nsDisplayMathMLBoundingMetrics() {
469 MOZ_COUNT_DTOR(nsDisplayMathMLBoundingMetrics);
471 #endif
473 virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
474 const nsRect& aDirtyRect);
475 NS_DISPLAY_DECL_NAME("MathMLBoundingMetrics")
476 private:
477 nsRect mRect;
480 void nsDisplayMathMLBoundingMetrics::Paint(nsDisplayListBuilder* aBuilder,
481 nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
483 aCtx->SetColor(NS_RGB(0,0,255));
484 aCtx->DrawRect(mRect + aBuilder->ToReferenceFrame(mFrame));
487 nsresult
488 nsMathMLFrame::DisplayBoundingMetrics(nsDisplayListBuilder* aBuilder,
489 nsIFrame* aFrame, const nsPoint& aPt,
490 const nsBoundingMetrics& aMetrics,
491 const nsDisplayListSet& aLists) {
492 if (!NS_MATHML_PAINT_BOUNDING_METRICS(mPresentationData.flags))
493 return NS_OK;
495 nscoord x = aPt.x + aMetrics.leftBearing;
496 nscoord y = aPt.y - aMetrics.ascent;
497 nscoord w = aMetrics.rightBearing - aMetrics.leftBearing;
498 nscoord h = aMetrics.ascent + aMetrics.descent;
500 return aLists.Content()->AppendNewToTop(new (aBuilder)
501 nsDisplayMathMLBoundingMetrics(this, nsRect(x,y,w,h)));
503 #endif
505 class nsDisplayMathMLBar : public nsDisplayItem {
506 public:
507 nsDisplayMathMLBar(nsIFrame* aFrame, const nsRect& aRect)
508 : nsDisplayItem(aFrame), mRect(aRect) {
509 MOZ_COUNT_CTOR(nsDisplayMathMLBar);
511 #ifdef NS_BUILD_REFCNT_LOGGING
512 virtual ~nsDisplayMathMLBar() {
513 MOZ_COUNT_DTOR(nsDisplayMathMLBar);
515 #endif
517 virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
518 const nsRect& aDirtyRect);
519 NS_DISPLAY_DECL_NAME("MathMLBar")
520 private:
521 nsRect mRect;
524 void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder,
525 nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
527 // paint the bar with the current text color
528 aCtx->SetColor(mFrame->GetStyleColor()->mColor);
529 aCtx->FillRect(mRect + aBuilder->ToReferenceFrame(mFrame));
532 nsresult
533 nsMathMLFrame::DisplayBar(nsDisplayListBuilder* aBuilder,
534 nsIFrame* aFrame, const nsRect& aRect,
535 const nsDisplayListSet& aLists) {
536 if (!aFrame->GetStyleVisibility()->IsVisible() || aRect.IsEmpty())
537 return NS_OK;
539 return aLists.Content()->AppendNewToTop(new (aBuilder)
540 nsDisplayMathMLBar(aFrame, aRect));