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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is Mozilla MathML Project.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Roger B. Sidje <rbs@maths.uq.edu.au>
24 : * David J. Fiddes <D.J.Fiddes@hw.ac.uk>
25 : * Shyjan Mahamud <mahamud@cs.cmu.edu>
26 : * Pierre Phaneuf <pp@ludusdesign.com>
27 : * Frederic Wang <fred.wang@free.fr>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : #include "nsCOMPtr.h"
44 : #include "nsFrame.h"
45 : #include "nsPresContext.h"
46 : #include "nsStyleContext.h"
47 : #include "nsStyleConsts.h"
48 : #include "nsRenderingContext.h"
49 : #include "nsContentUtils.h"
50 :
51 : #include "nsMathMLmoFrame.h"
52 :
53 : //
54 : // <mo> -- operator, fence, or separator - implementation
55 : //
56 :
57 : // additional style context to be used by our MathMLChar.
58 : #define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX 0
59 :
60 : nsIFrame*
61 0 : NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
62 : {
63 0 : return new (aPresShell) nsMathMLmoFrame(aContext);
64 : }
65 :
66 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmoFrame)
67 :
68 0 : nsMathMLmoFrame::~nsMathMLmoFrame()
69 : {
70 0 : }
71 :
72 : static const PRUnichar kInvisibleComma = PRUnichar(0x200B); // a.k.a. ZERO WIDTH SPACE
73 : static const PRUnichar kApplyFunction = PRUnichar(0x2061);
74 : static const PRUnichar kInvisibleTimes = PRUnichar(0x2062);
75 : static const PRUnichar kNullCh = PRUnichar('\0');
76 :
77 : eMathMLFrameType
78 0 : nsMathMLmoFrame::GetMathMLFrameType()
79 : {
80 : return NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)
81 : ? eMathMLFrameType_OperatorInvisible
82 0 : : eMathMLFrameType_OperatorOrdinary;
83 : }
84 :
85 : // since a mouse click implies selection, we cannot just rely on the
86 : // frame's state bit in our child text frame. So we will first check
87 : // its selected state bit, and use this little helper to double check.
88 : bool
89 0 : nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame)
90 : {
91 0 : NS_ASSERTION(aFrame, "null arg");
92 0 : if (!aFrame || !aFrame->IsSelected())
93 0 : return false;
94 :
95 0 : const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection();
96 : SelectionDetails* details =
97 0 : frameSelection->LookUpSelection(aFrame->GetContent(), 0, 1, true);
98 :
99 0 : if (!details)
100 0 : return false;
101 :
102 0 : while (details) {
103 0 : SelectionDetails* next = details->mNext;
104 0 : delete details;
105 0 : details = next;
106 : }
107 0 : return true;
108 : }
109 :
110 : bool
111 0 : nsMathMLmoFrame::UseMathMLChar()
112 : {
113 : return (NS_MATHML_OPERATOR_GET_FORM(mFlags) &&
114 : NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) ||
115 : NS_MATHML_OPERATOR_IS_CENTERED(mFlags) ||
116 0 : NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags);
117 : }
118 :
119 : NS_IMETHODIMP
120 0 : nsMathMLmoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
121 : const nsRect& aDirtyRect,
122 : const nsDisplayListSet& aLists)
123 : {
124 0 : nsresult rv = NS_OK;
125 0 : bool useMathMLChar = UseMathMLChar();
126 :
127 0 : if (!useMathMLChar) {
128 : // let the base class do everything
129 0 : rv = nsMathMLTokenFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
130 0 : NS_ENSURE_SUCCESS(rv, rv);
131 : } else {
132 0 : rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
133 0 : NS_ENSURE_SUCCESS(rv, rv);
134 :
135 : // make our char selected if our inner child text frame is selected
136 0 : bool isSelected = false;
137 0 : nsRect selectedRect;
138 0 : nsIFrame* firstChild = mFrames.FirstChild();
139 0 : if (IsFrameInSelection(firstChild)) {
140 0 : selectedRect = firstChild->GetRect();
141 0 : isSelected = true;
142 : }
143 0 : rv = mMathMLChar.Display(aBuilder, this, aLists, isSelected ? &selectedRect : nsnull);
144 0 : NS_ENSURE_SUCCESS(rv, rv);
145 :
146 : #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
147 : // for visual debug
148 : rv = DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
149 : #endif
150 : }
151 0 : return rv;
152 : }
153 :
154 : // get the text that we enclose and setup our nsMathMLChar
155 : void
156 0 : nsMathMLmoFrame::ProcessTextData()
157 : {
158 0 : mFlags = 0;
159 :
160 0 : nsAutoString data;
161 0 : nsContentUtils::GetNodeTextContent(mContent, false, data);
162 0 : PRInt32 length = data.Length();
163 0 : PRUnichar ch = (length == 0) ? kNullCh : data[0];
164 :
165 0 : if ((length == 1) &&
166 : (ch == kInvisibleComma ||
167 : ch == kApplyFunction ||
168 : ch == kInvisibleTimes)) {
169 0 : mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
170 : }
171 :
172 : // don't bother doing anything special if we don't have a
173 : // single child with a visible text content
174 0 : nsPresContext* presContext = PresContext();
175 0 : if (NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags) || mFrames.GetLength() != 1) {
176 0 : data.Truncate(); // empty data to reset the char
177 0 : mMathMLChar.SetData(presContext, data);
178 0 : ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar, false);
179 : return;
180 : }
181 :
182 : // special... in math mode, the usual minus sign '-' looks too short, so
183 : // what we do here is to remap <mo>-</mo> to the official Unicode minus
184 : // sign (U+2212) which looks much better. For background on this, see
185 : // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1
186 0 : if (1 == length && ch == '-') {
187 0 : ch = 0x2212;
188 0 : data = ch;
189 : }
190 :
191 : // cache the special bits: mutable, accent, movablelimits, centered.
192 : // we need to do this in anticipation of other requirements, and these
193 : // bits don't change. Do not reset these bits unless the text gets changed.
194 :
195 : // lookup all the forms under which the operator is listed in the dictionary,
196 : // and record whether the operator has accent="true" or movablelimits="true"
197 : nsOperatorFlags flags[4];
198 : float lspace[4], rspace[4];
199 0 : nsMathMLOperators::LookupOperators(data, flags, lspace, rspace);
200 : nsOperatorFlags allFlags =
201 0 : flags[NS_MATHML_OPERATOR_FORM_INFIX] |
202 0 : flags[NS_MATHML_OPERATOR_FORM_POSTFIX] |
203 0 : flags[NS_MATHML_OPERATOR_FORM_PREFIX];
204 :
205 0 : mFlags |= allFlags & NS_MATHML_OPERATOR_ACCENT;
206 0 : mFlags |= allFlags & NS_MATHML_OPERATOR_MOVABLELIMITS;
207 :
208 : bool isMutable =
209 : NS_MATHML_OPERATOR_IS_STRETCHY(allFlags) ||
210 0 : NS_MATHML_OPERATOR_IS_LARGEOP(allFlags);
211 0 : if (isMutable)
212 0 : mFlags |= NS_MATHML_OPERATOR_MUTABLE;
213 :
214 : // see if this is an operator that should be centered to cater for
215 : // fonts that are not math-aware
216 0 : if (1 == length) {
217 0 : if ((ch == '+') || (ch == '=') || (ch == '*') ||
218 : (ch == 0x2212) || // −
219 : (ch == 0x2264) || // ≤
220 : (ch == 0x2265) || // ≥
221 : (ch == 0x00D7)) { // ×
222 0 : mFlags |= NS_MATHML_OPERATOR_CENTERED;
223 : }
224 : }
225 :
226 : // cache the operator
227 0 : mMathMLChar.SetData(presContext, data);
228 0 : ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar, isMutable);
229 :
230 : // cache the native direction -- beware of bug 133429...
231 : // mEmbellishData.direction must always retain our native direction, whereas
232 : // mMathMLChar.GetStretchDirection() may change later, when Stretch() is called
233 0 : mEmbellishData.direction = mMathMLChar.GetStretchDirection();
234 : }
235 :
236 : // get our 'form' and lookup in the Operator Dictionary to fetch
237 : // our default data that may come from there. Then complete our setup
238 : // using attributes that we may have. To stay in sync, this function is
239 : // called very often. We depend on many things that may change around us.
240 : // However, we re-use unchanged values.
241 : void
242 0 : nsMathMLmoFrame::ProcessOperatorData()
243 : {
244 : // if we have been here before, we will just use our cached form
245 0 : nsOperatorFlags form = NS_MATHML_OPERATOR_GET_FORM(mFlags);
246 0 : nsAutoString value;
247 :
248 : // special bits are always kept in mFlags.
249 : // remember the mutable bit from ProcessTextData().
250 : // Some chars are listed under different forms in the dictionary,
251 : // and there could be a form under which the char is mutable.
252 : // If the char is the core of an embellished container, we will keep
253 : // it mutable irrespective of the form of the embellished container.
254 : // Also remember the other special bits that we want to carry forward.
255 : mFlags &= NS_MATHML_OPERATOR_MUTABLE |
256 : NS_MATHML_OPERATOR_ACCENT |
257 : NS_MATHML_OPERATOR_MOVABLELIMITS |
258 : NS_MATHML_OPERATOR_CENTERED |
259 0 : NS_MATHML_OPERATOR_INVISIBLE;
260 :
261 0 : if (!mEmbellishData.coreFrame) {
262 : // i.e., we haven't been here before, the default form is infix
263 0 : form = NS_MATHML_OPERATOR_FORM_INFIX;
264 :
265 : // reset everything so that we don't keep outdated values around
266 : // in case of dynamic changes
267 0 : mEmbellishData.flags = 0;
268 0 : mEmbellishData.coreFrame = nsnull;
269 0 : mEmbellishData.leadingSpace = 0;
270 0 : mEmbellishData.trailingSpace = 0;
271 0 : if (mMathMLChar.Length() != 1)
272 0 : mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
273 : // else... retain the native direction obtained in ProcessTextData()
274 :
275 0 : if (!mFrames.FirstChild()) {
276 : return;
277 : }
278 :
279 0 : mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR;
280 0 : mEmbellishData.coreFrame = this;
281 :
282 : // there are two particular things that we also need to record so that if our
283 : // parent is <mover>, <munder>, or <munderover>, they will treat us properly:
284 : // 1) do we have accent="true"
285 : // 2) do we have movablelimits="true"
286 :
287 : // they need the extra information to decide how to treat their scripts/limits
288 : // (note: <mover>, <munder>, or <munderover> need not necessarily be our
289 : // direct parent -- case of embellished operators)
290 :
291 : // default values from the Operator Dictionary were obtained in ProcessTextData()
292 : // and these special bits are always kept in mFlags
293 0 : if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags))
294 0 : mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
295 0 : if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags))
296 0 : mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
297 :
298 : // see if the accent attribute is there
299 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::accent_,
300 0 : value);
301 0 : if (value.EqualsLiteral("true"))
302 0 : mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
303 0 : else if (value.EqualsLiteral("false"))
304 0 : mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT;
305 :
306 : // see if the movablelimits attribute is there
307 : GetAttribute(mContent, mPresentationData.mstyle,
308 0 : nsGkAtoms::movablelimits_, value);
309 0 : if (value.EqualsLiteral("true"))
310 0 : mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
311 0 : else if (value.EqualsLiteral("false"))
312 0 : mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS;
313 :
314 : // ---------------------------------------------------------------------
315 : // we will be called again to re-sync the rest of our state next time...
316 : // (nobody needs the other values below at this stage)
317 0 : mFlags |= form;
318 : return;
319 : }
320 :
321 0 : nsPresContext* presContext = PresContext();
322 :
323 : // beware of bug 133814 - there is a two-way dependency in the
324 : // embellished hierarchy: our embellished ancestors need to set
325 : // their flags based on some of our state (set above), and here we
326 : // need to re-sync our 'form' depending on our outermost embellished
327 : // container. A null form here means that an earlier attempt to stretch
328 : // our mMathMLChar failed, in which case we don't bother re-stretching again
329 0 : if (form) {
330 : // get our outermost embellished container and its parent.
331 : // (we ensure that we are the core, not just a sibling of the core)
332 0 : nsIFrame* embellishAncestor = this;
333 0 : nsEmbellishData embellishData;
334 0 : nsIFrame* parentAncestor = this;
335 0 : do {
336 0 : embellishAncestor = parentAncestor;
337 0 : parentAncestor = embellishAncestor->GetParent();
338 0 : GetEmbellishDataFrom(parentAncestor, embellishData);
339 : } while (embellishData.coreFrame == this);
340 :
341 : // flag if we have an embellished ancestor
342 0 : if (embellishAncestor != this)
343 0 : mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
344 : else
345 0 : mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
346 :
347 : // find the position of our outermost embellished container w.r.t
348 : // its siblings.
349 :
350 0 : nsIFrame* nextSibling = embellishAncestor->GetNextSibling();
351 0 : nsIFrame* prevSibling = embellishAncestor->GetPrevSibling();
352 :
353 : // flag to distinguish from a real infix
354 0 : if (!prevSibling && !nextSibling)
355 0 : mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
356 : else
357 0 : mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
358 :
359 : // find our form
360 0 : form = NS_MATHML_OPERATOR_FORM_INFIX;
361 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::form,
362 0 : value);
363 0 : if (!value.IsEmpty()) {
364 0 : if (value.EqualsLiteral("prefix"))
365 0 : form = NS_MATHML_OPERATOR_FORM_PREFIX;
366 0 : else if (value.EqualsLiteral("postfix"))
367 0 : form = NS_MATHML_OPERATOR_FORM_POSTFIX;
368 : }
369 : else {
370 : // set our form flag depending on the position
371 0 : if (!prevSibling && nextSibling)
372 0 : form = NS_MATHML_OPERATOR_FORM_PREFIX;
373 0 : else if (prevSibling && !nextSibling)
374 0 : form = NS_MATHML_OPERATOR_FORM_POSTFIX;
375 : }
376 0 : mFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the old form bits
377 0 : mFlags |= form;
378 :
379 : // lookup the operator dictionary
380 0 : float lspace = 0.0f;
381 0 : float rspace = 0.0f;
382 0 : nsAutoString data;
383 0 : mMathMLChar.GetData(data);
384 0 : bool found = nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace);
385 0 : if (found && (lspace || rspace)) {
386 : // cache the default values of lspace & rspace that we get from the dictionary.
387 : // since these values are relative to the 'em' unit, convert to twips now
388 : nscoord em;
389 0 : nsRefPtr<nsFontMetrics> fm;
390 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
391 0 : GetEmHeight(fm, em);
392 :
393 0 : mEmbellishData.leadingSpace = NSToCoordRound(lspace * em);
394 0 : mEmbellishData.trailingSpace = NSToCoordRound(rspace * em);
395 :
396 : // tuning if we don't want too much extra space when we are a script.
397 : // (with its fonts, TeX sets lspace=0 & rspace=0 as soon as scriptlevel>0.
398 : // Our fonts can be anything, so...)
399 0 : if (GetStyleFont()->mScriptLevel > 0) {
400 0 : if (NS_MATHML_OPERATOR_EMBELLISH_IS_ISOLATED(mFlags)) {
401 : // could be an isolated accent or script, e.g., x^{+}, just zero out
402 0 : mEmbellishData.leadingSpace = 0;
403 0 : mEmbellishData.trailingSpace = 0;
404 : }
405 0 : else if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
406 0 : mEmbellishData.leadingSpace /= 2;
407 0 : mEmbellishData.trailingSpace /= 2;
408 : }
409 : }
410 : }
411 : }
412 :
413 : // If we are an accent without explicit lspace="." or rspace=".",
414 : // we will ignore our default leading/trailing space
415 :
416 : // lspace = number h-unit | namedspace
417 0 : nscoord leadingSpace = mEmbellishData.leadingSpace;
418 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::lspace_,
419 0 : value);
420 0 : if (!value.IsEmpty()) {
421 0 : nsCSSValue cssValue;
422 0 : if (ParseNumericValue(value, cssValue) ||
423 0 : ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
424 : {
425 0 : if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
426 0 : leadingSpace = 0;
427 0 : else if (cssValue.IsLengthUnit())
428 0 : leadingSpace = CalcLength(presContext, mStyleContext, cssValue);
429 0 : mFlags |= NS_MATHML_OPERATOR_LSPACE_ATTR;
430 : }
431 : }
432 :
433 : // rspace = number h-unit | namedspace
434 0 : nscoord trailingSpace = mEmbellishData.trailingSpace;
435 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::rspace_,
436 0 : value);
437 0 : if (!value.IsEmpty()) {
438 0 : nsCSSValue cssValue;
439 0 : if (ParseNumericValue(value, cssValue) ||
440 0 : ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
441 : {
442 0 : if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
443 0 : trailingSpace = 0;
444 0 : else if (cssValue.IsLengthUnit())
445 0 : trailingSpace = CalcLength(presContext, mStyleContext, cssValue);
446 0 : mFlags |= NS_MATHML_OPERATOR_RSPACE_ATTR;
447 : }
448 : }
449 :
450 : // little extra tuning to round lspace & rspace to at least a pixel so that
451 : // operators don't look as if they are colliding with their operands
452 0 : if (leadingSpace || trailingSpace) {
453 0 : nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
454 0 : if (leadingSpace && leadingSpace < onePixel)
455 0 : leadingSpace = onePixel;
456 0 : if (trailingSpace && trailingSpace < onePixel)
457 0 : trailingSpace = onePixel;
458 : }
459 :
460 : // the values that we get from our attributes override the dictionary
461 0 : mEmbellishData.leadingSpace = leadingSpace;
462 0 : mEmbellishData.trailingSpace = trailingSpace;
463 :
464 : // Now see if there are user-defined attributes that override the dictionary.
465 : // XXX If an attribute can be forced to be true when it is false in the
466 : // dictionary, then the following code has to change...
467 :
468 : // For each attribute overriden by the user, turn off its bit flag.
469 : // symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form
470 : // special: accent and movablelimits are handled above,
471 : // don't process them here
472 :
473 : GetAttribute(mContent, mPresentationData.mstyle,
474 0 : nsGkAtoms::stretchy_, value);
475 0 : if (value.EqualsLiteral("false")) {
476 0 : mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
477 0 : } else if (value.EqualsLiteral("true")) {
478 0 : mFlags |= NS_MATHML_OPERATOR_STRETCHY;
479 : }
480 0 : if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
481 : GetAttribute(mContent, mPresentationData.mstyle,
482 0 : nsGkAtoms::fence_, value);
483 0 : if (value.EqualsLiteral("false"))
484 0 : mFlags &= ~NS_MATHML_OPERATOR_FENCE;
485 : }
486 : GetAttribute(mContent, mPresentationData.mstyle,
487 0 : nsGkAtoms::largeop_, value);
488 0 : if (value.EqualsLiteral("false")) {
489 0 : mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
490 0 : } else if (value.EqualsLiteral("true")) {
491 0 : mFlags |= NS_MATHML_OPERATOR_LARGEOP;
492 : }
493 0 : if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
494 : GetAttribute(mContent, mPresentationData.mstyle,
495 0 : nsGkAtoms::separator_, value);
496 0 : if (value.EqualsLiteral("false"))
497 0 : mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
498 : }
499 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::symmetric_,
500 0 : value);
501 0 : if (value.EqualsLiteral("false"))
502 0 : mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
503 0 : else if (value.EqualsLiteral("true"))
504 0 : mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
505 :
506 : // minsize = number [ v-unit | h-unit ] | namedspace
507 0 : mMinSize = 0.0;
508 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::minsize_,
509 0 : value);
510 0 : if (!value.IsEmpty()) {
511 0 : nsCSSValue cssValue;
512 0 : if (ParseNumericValue(value, cssValue) ||
513 0 : ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
514 : {
515 0 : nsCSSUnit unit = cssValue.GetUnit();
516 0 : if (eCSSUnit_Number == unit)
517 0 : mMinSize = cssValue.GetFloatValue();
518 0 : else if (eCSSUnit_Percent == unit)
519 0 : mMinSize = cssValue.GetPercentValue();
520 0 : else if (eCSSUnit_Null != unit) {
521 0 : mMinSize = float(CalcLength(presContext, mStyleContext, cssValue));
522 0 : mFlags |= NS_MATHML_OPERATOR_MINSIZE_ABSOLUTE;
523 : }
524 :
525 0 : if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
526 : // see if the multiplicative inheritance should be from <mstyle>
527 : GetAttribute(nsnull, mPresentationData.mstyle,
528 0 : nsGkAtoms::minsize_, value);
529 0 : if (!value.IsEmpty()) {
530 0 : if (ParseNumericValue(value, cssValue)) {
531 0 : if (cssValue.IsLengthUnit()) {
532 0 : mMinSize *= float(CalcLength(presContext, mStyleContext, cssValue));
533 0 : mFlags |= NS_MATHML_OPERATOR_MINSIZE_ABSOLUTE;
534 : }
535 : }
536 : }
537 : }
538 : }
539 : }
540 :
541 : // maxsize = number [ v-unit | h-unit ] | namedspace | infinity
542 0 : mMaxSize = NS_MATHML_OPERATOR_SIZE_INFINITY;
543 : GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::maxsize_,
544 0 : value);
545 0 : if (!value.IsEmpty()) {
546 0 : nsCSSValue cssValue;
547 0 : if (ParseNumericValue(value, cssValue) ||
548 0 : ParseNamedSpaceValue(mPresentationData.mstyle, value, cssValue))
549 : {
550 0 : nsCSSUnit unit = cssValue.GetUnit();
551 0 : if (eCSSUnit_Number == unit)
552 0 : mMaxSize = cssValue.GetFloatValue();
553 0 : else if (eCSSUnit_Percent == unit)
554 0 : mMaxSize = cssValue.GetPercentValue();
555 0 : else if (eCSSUnit_Null != unit) {
556 0 : mMaxSize = float(CalcLength(presContext, mStyleContext, cssValue));
557 0 : mFlags |= NS_MATHML_OPERATOR_MAXSIZE_ABSOLUTE;
558 : }
559 :
560 0 : if ((eCSSUnit_Number == unit) || (eCSSUnit_Percent == unit)) {
561 : // see if the multiplicative inheritance should be from <mstyle>
562 : GetAttribute(nsnull, mPresentationData.mstyle,
563 0 : nsGkAtoms::maxsize_, value);
564 0 : if (!value.IsEmpty()) {
565 0 : if (ParseNumericValue(value, cssValue)) {
566 0 : if (cssValue.IsLengthUnit()) {
567 0 : mMaxSize *= float(CalcLength(presContext, mStyleContext, cssValue));
568 0 : mFlags |= NS_MATHML_OPERATOR_MAXSIZE_ABSOLUTE;
569 : }
570 : }
571 : }
572 : }
573 : }
574 : }
575 : }
576 :
577 : static PRUint32
578 0 : GetStretchHint(nsOperatorFlags aFlags, nsPresentationData aPresentationData,
579 : bool aIsVertical)
580 : {
581 0 : PRUint32 stretchHint = NS_STRETCH_NONE;
582 : // See if it is okay to stretch,
583 : // starting from what the Operator Dictionary said
584 0 : if (NS_MATHML_OPERATOR_IS_MUTABLE(aFlags)) {
585 : // set the largeop or largeopOnly flags to suitably cover all the
586 : // 8 possible cases depending on whether displaystyle, largeop,
587 : // stretchy are true or false (see bug 69325).
588 : // . largeopOnly is taken if largeop=true and stretchy=false
589 : // . largeop is taken if largeop=true and stretchy=true
590 0 : if (NS_MATHML_IS_DISPLAYSTYLE(aPresentationData.flags) &&
591 : NS_MATHML_OPERATOR_IS_LARGEOP(aFlags)) {
592 0 : stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!)
593 0 : if (NS_MATHML_OPERATOR_IS_INTEGRAL(aFlags)) {
594 0 : stretchHint |= NS_STRETCH_INTEGRAL;
595 : }
596 0 : if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) {
597 0 : stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER;
598 : }
599 : }
600 0 : else if(NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) {
601 0 : if (aIsVertical) {
602 : // TeX hint. Can impact some sloppy markups missing <mrow></mrow>
603 0 : stretchHint = NS_STRETCH_NEARER;
604 : }
605 : else {
606 0 : stretchHint = NS_STRETCH_NORMAL;
607 : }
608 : }
609 : // else if the stretchy and largeop attributes have been disabled,
610 : // the operator is not mutable
611 : }
612 0 : return stretchHint;
613 : }
614 :
615 : // NOTE: aDesiredStretchSize is an IN/OUT parameter
616 : // On input - it contains our current size
617 : // On output - the same size or the new size that we want
618 : NS_IMETHODIMP
619 0 : nsMathMLmoFrame::Stretch(nsRenderingContext& aRenderingContext,
620 : nsStretchDirection aStretchDirection,
621 : nsBoundingMetrics& aContainerSize,
622 : nsHTMLReflowMetrics& aDesiredStretchSize)
623 : {
624 0 : if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
625 0 : NS_WARNING("it is wrong to fire stretch more than once on a frame");
626 0 : return NS_OK;
627 : }
628 0 : mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
629 :
630 0 : nsIFrame* firstChild = mFrames.FirstChild();
631 :
632 : // get the axis height;
633 0 : nsRefPtr<nsFontMetrics> fm;
634 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
635 0 : aRenderingContext.SetFont(fm);
636 : nscoord axisHeight, height;
637 0 : GetAxisHeight(aRenderingContext, fm, axisHeight);
638 :
639 : // get the leading to be left at the top and the bottom of the stretched char
640 : // this seems more reliable than using fm->GetLeading() on suspicious fonts
641 : nscoord em;
642 0 : GetEmHeight(fm, em);
643 0 : nscoord leading = NSToCoordRound(0.2f * em);
644 :
645 : // Operators that are stretchy, or those that are to be centered
646 : // to cater for fonts that are not math-aware, are handled by the MathMLChar
647 : // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time)
648 0 : bool useMathMLChar = UseMathMLChar();
649 :
650 0 : nsBoundingMetrics charSize;
651 0 : nsBoundingMetrics container = aDesiredStretchSize.mBoundingMetrics;
652 0 : bool isVertical = false;
653 :
654 0 : if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) ||
655 : (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT)) &&
656 : (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL)) {
657 0 : isVertical = true;
658 : }
659 :
660 : PRUint32 stretchHint =
661 0 : GetStretchHint(mFlags, mPresentationData, isVertical);
662 :
663 0 : if (useMathMLChar) {
664 0 : nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics;
665 :
666 0 : if (stretchHint != NS_STRETCH_NONE) {
667 :
668 0 : container = aContainerSize;
669 :
670 : // some adjustments if the operator is symmetric and vertical
671 :
672 0 : if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
673 : // we need to center about the axis
674 : nscoord delta = NS_MAX(container.ascent - axisHeight,
675 0 : container.descent + axisHeight);
676 0 : container.ascent = delta + axisHeight;
677 0 : container.descent = delta - axisHeight;
678 :
679 : // get ready in case we encounter user-desired min-max size
680 : delta = NS_MAX(initialSize.ascent - axisHeight,
681 0 : initialSize.descent + axisHeight);
682 0 : initialSize.ascent = delta + axisHeight;
683 0 : initialSize.descent = delta - axisHeight;
684 : }
685 :
686 : // check for user-desired min-max size
687 :
688 0 : if (mMaxSize != NS_MATHML_OPERATOR_SIZE_INFINITY && mMaxSize > 0.0f) {
689 : // if we are here, there is a user defined maxsize ...
690 : //XXX Set stretchHint = NS_STRETCH_NORMAL? to honor the maxsize as close as possible?
691 0 : if (NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)) {
692 : // there is an explicit value like maxsize="20pt"
693 : // try to maintain the aspect ratio of the char
694 0 : float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent);
695 : container.ascent =
696 0 : NS_MIN(container.ascent, nscoord(initialSize.ascent * aspect));
697 : container.descent =
698 0 : NS_MIN(container.descent, nscoord(initialSize.descent * aspect));
699 : // below we use a type cast instead of a conversion to avoid a VC++ bug
700 : // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP
701 : container.width =
702 0 : NS_MIN(container.width, (nscoord)mMaxSize);
703 : }
704 : else { // multiplicative value
705 : container.ascent =
706 0 : NS_MIN(container.ascent, nscoord(initialSize.ascent * mMaxSize));
707 : container.descent =
708 0 : NS_MIN(container.descent, nscoord(initialSize.descent * mMaxSize));
709 : container.width =
710 0 : NS_MIN(container.width, nscoord(initialSize.width * mMaxSize));
711 : }
712 :
713 0 : if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
714 : // re-adjust to align the char with the bottom of the initial container
715 0 : height = container.ascent + container.descent;
716 0 : container.descent = aContainerSize.descent;
717 0 : container.ascent = height - container.descent;
718 : }
719 : }
720 :
721 0 : if (mMinSize > 0.0f) {
722 : // if we are here, there is a user defined minsize ...
723 : // always allow the char to stretch in its natural direction,
724 : // even if it is different from the caller's direction
725 0 : if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT &&
726 : aStretchDirection != mEmbellishData.direction) {
727 0 : aStretchDirection = NS_STRETCH_DIRECTION_DEFAULT;
728 : // but when we are not honoring the requested direction
729 : // we should not use the caller's container size either
730 0 : container = initialSize;
731 : }
732 0 : if (NS_MATHML_OPERATOR_MINSIZE_IS_ABSOLUTE(mFlags)) {
733 : // there is an explicit value like minsize="20pt"
734 : // try to maintain the aspect ratio of the char
735 0 : float aspect = mMinSize / float(initialSize.ascent + initialSize.descent);
736 : container.ascent =
737 0 : NS_MAX(container.ascent, nscoord(initialSize.ascent * aspect));
738 : container.descent =
739 0 : NS_MAX(container.descent, nscoord(initialSize.descent * aspect));
740 : container.width =
741 0 : NS_MAX(container.width, (nscoord)mMinSize);
742 : }
743 : else { // multiplicative value
744 : container.ascent =
745 0 : NS_MAX(container.ascent, nscoord(initialSize.ascent * mMinSize));
746 : container.descent =
747 0 : NS_MAX(container.descent, nscoord(initialSize.descent * mMinSize));
748 : container.width =
749 0 : NS_MAX(container.width, nscoord(initialSize.width * mMinSize));
750 : }
751 :
752 0 : if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) {
753 : // re-adjust to align the char with the bottom of the initial container
754 0 : height = container.ascent + container.descent;
755 0 : container.descent = aContainerSize.descent;
756 0 : container.ascent = height - container.descent;
757 : }
758 : }
759 : }
760 :
761 : // let the MathMLChar stretch itself...
762 : nsresult res = mMathMLChar.Stretch(PresContext(), aRenderingContext,
763 : aStretchDirection, container, charSize,
764 : stretchHint,
765 : NS_MATHML_IS_RTL(mPresentationData.
766 0 : flags));
767 0 : if (NS_FAILED(res)) {
768 : // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed)
769 : // clear our 'form' to behave as if the operator wasn't in the dictionary
770 0 : mFlags &= ~NS_MATHML_OPERATOR_FORM;
771 0 : useMathMLChar = false;
772 : }
773 : }
774 :
775 : // Child frames of invisble operators are not reflowed
776 0 : if (!NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)) {
777 : // Place our children using the default method
778 : // This will allow our child text frame to get its DidReflow()
779 0 : nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize);
780 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
781 : // Make sure the child frames get their DidReflow() calls.
782 0 : DidReflowChildren(mFrames.FirstChild());
783 : }
784 : }
785 :
786 0 : if (useMathMLChar) {
787 : // update our bounding metrics... it becomes that of our MathML char
788 0 : mBoundingMetrics = charSize;
789 :
790 : // if the returned direction is 'unsupported', the char didn't actually change.
791 : // So we do the centering only if necessary
792 0 : if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED ||
793 : NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
794 :
795 : bool largeopOnly =
796 : (NS_STRETCH_LARGEOP & stretchHint) != 0 &&
797 0 : (NS_STRETCH_VARIABLE_MASK & stretchHint) == 0;
798 :
799 0 : if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
800 : // the desired size returned by mMathMLChar maybe different
801 : // from the size of the container.
802 : // the mMathMLChar.mRect.y calculation is subtle, watch out!!!
803 :
804 0 : height = mBoundingMetrics.ascent + mBoundingMetrics.descent;
805 0 : if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) ||
806 : NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) {
807 : // For symmetric and vertical operators, or for operators that are always
808 : // centered ('+', '*', etc) we want to center about the axis of the container
809 0 : mBoundingMetrics.descent = height/2 - axisHeight;
810 0 : } else if (!largeopOnly) {
811 : // Align the center of the char with the center of the container
812 : mBoundingMetrics.descent = height/2 +
813 0 : (container.ascent + container.descent)/2 - container.ascent;
814 : } // else align the baselines
815 0 : mBoundingMetrics.ascent = height - mBoundingMetrics.descent;
816 : }
817 : }
818 : }
819 :
820 : // Fixup for the final height.
821 : // On one hand, our stretchy height can sometimes be shorter than surrounding
822 : // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading|
823 : // that is smaller than the ASCII's ascent, hence when painting the background
824 : // later, it won't look uniform along the line.
825 : // On the other hand, sometimes we may leave too much gap when our glyph happens
826 : // to come from a font with tall glyphs. For example, since CMEX10 has very tall
827 : // glyphs, its natural font metrics are large, even if we pick a small glyph
828 : // whose size is comparable to the size of a normal ASCII glyph.
829 : // So to avoid uneven spacing in either of these two cases, we use the height
830 : // of the ASCII font as a reference and try to match it if possible.
831 :
832 : // special case for accents... keep them short to improve mouse operations...
833 : // an accent can only be the non-first child of <mover>, <munder>, <munderover>
834 : bool isAccent =
835 0 : NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags);
836 0 : if (isAccent) {
837 0 : nsEmbellishData parentData;
838 0 : GetEmbellishDataFrom(mParent, parentData);
839 : isAccent =
840 : (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) ||
841 : NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) &&
842 0 : parentData.coreFrame != this;
843 : }
844 0 : if (isAccent && firstChild) {
845 : // see bug 188467 for what is going on here
846 0 : nscoord dy = aDesiredStretchSize.ascent - (mBoundingMetrics.ascent + leading);
847 0 : aDesiredStretchSize.ascent = mBoundingMetrics.ascent + leading;
848 0 : aDesiredStretchSize.height = aDesiredStretchSize.ascent + mBoundingMetrics.descent;
849 :
850 0 : firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy));
851 : }
852 0 : else if (useMathMLChar) {
853 0 : nscoord ascent = fm->MaxAscent();
854 0 : nscoord descent = fm->MaxDescent();
855 0 : aDesiredStretchSize.ascent = NS_MAX(mBoundingMetrics.ascent + leading, ascent);
856 : aDesiredStretchSize.height = aDesiredStretchSize.ascent +
857 0 : NS_MAX(mBoundingMetrics.descent + leading, descent);
858 : }
859 0 : aDesiredStretchSize.width = mBoundingMetrics.width;
860 0 : aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics;
861 0 : mReference.x = 0;
862 0 : mReference.y = aDesiredStretchSize.ascent;
863 : // Place our mMathMLChar, its origin is in our coordinate system
864 0 : if (useMathMLChar) {
865 0 : nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent;
866 0 : mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent));
867 : }
868 :
869 : // Before we leave... there is a last item in the check-list:
870 : // If our parent is not embellished, it means we are the outermost embellished
871 : // container and so we put the spacing, otherwise we don't include the spacing,
872 : // the outermost embellished container will take care of it.
873 :
874 0 : if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
875 :
876 : // Account the spacing if we are not an accent with explicit attributes
877 0 : nscoord leadingSpace = mEmbellishData.leadingSpace;
878 0 : if (isAccent && !NS_MATHML_OPERATOR_HAS_LSPACE_ATTR(mFlags)) {
879 0 : leadingSpace = 0;
880 : }
881 0 : nscoord trailingSpace = mEmbellishData.trailingSpace;
882 0 : if (isAccent && !NS_MATHML_OPERATOR_HAS_RSPACE_ATTR(mFlags)) {
883 0 : trailingSpace = 0;
884 : }
885 :
886 0 : mBoundingMetrics.width += leadingSpace + trailingSpace;
887 0 : aDesiredStretchSize.width = mBoundingMetrics.width;
888 0 : aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
889 :
890 : nscoord dx = (NS_MATHML_IS_RTL(mPresentationData.flags) ?
891 0 : trailingSpace : leadingSpace);
892 0 : if (dx) {
893 : // adjust the offsets
894 0 : mBoundingMetrics.leftBearing += dx;
895 0 : mBoundingMetrics.rightBearing += dx;
896 0 : aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
897 0 : aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
898 :
899 0 : if (useMathMLChar) {
900 0 : nsRect rect;
901 0 : mMathMLChar.GetRect(rect);
902 : mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y,
903 0 : rect.width, rect.height));
904 : }
905 : else {
906 0 : nsIFrame* childFrame = firstChild;
907 0 : while (childFrame) {
908 : childFrame->SetPosition(childFrame->GetPosition() +
909 0 : nsPoint(dx, 0));
910 0 : childFrame = childFrame->GetNextSibling();
911 : }
912 : }
913 : }
914 : }
915 :
916 : // Finished with these:
917 0 : ClearSavedChildMetrics();
918 : // Set our overflow area
919 0 : GatherAndStoreOverflow(&aDesiredStretchSize);
920 :
921 : // There used to be code here to change the height of the child frame to
922 : // change the caret height, but the text frame that manages the caret is now
923 : // not a direct child but wrapped in a block frame. See also bug 412033.
924 :
925 0 : return NS_OK;
926 : }
927 :
928 : NS_IMETHODIMP
929 0 : nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent)
930 : {
931 : // retain our native direction, it only changes if our text content changes
932 0 : nsStretchDirection direction = mEmbellishData.direction;
933 0 : nsMathMLTokenFrame::InheritAutomaticData(aParent);
934 0 : mEmbellishData.direction = direction;
935 0 : return NS_OK;
936 : }
937 :
938 : NS_IMETHODIMP
939 0 : nsMathMLmoFrame::TransmitAutomaticData()
940 : {
941 : // this will cause us to re-sync our flags from scratch
942 : // but our returned 'form' is still not final (bug 133429), it will
943 : // be recomputed to its final value during the next call in Reflow()
944 0 : mEmbellishData.coreFrame = nsnull;
945 0 : ProcessOperatorData();
946 0 : return NS_OK;
947 : }
948 :
949 : NS_IMETHODIMP
950 0 : nsMathMLmoFrame::Reflow(nsPresContext* aPresContext,
951 : nsHTMLReflowMetrics& aDesiredSize,
952 : const nsHTMLReflowState& aReflowState,
953 : nsReflowStatus& aStatus)
954 : {
955 : // certain values use units that depend on our style context, so
956 : // it is safer to just process the whole lot here
957 0 : ProcessOperatorData();
958 :
959 : // play safe by not passing invisible operators to the font subsystem because
960 : // some platforms risk selecting strange glyphs for them and give bad inter-space
961 0 : if (NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)) {
962 : // return empty space for now, but this is not yet final since there
963 : // can be lspace and rspace attributes that reclaim some room.
964 : // These will be dealt with later in Stretch().
965 0 : aDesiredSize.width = 0;
966 0 : aDesiredSize.height = 0;
967 0 : aDesiredSize.ascent = 0;
968 0 : aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
969 0 : aStatus = NS_FRAME_COMPLETE;
970 :
971 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
972 0 : return NS_OK;
973 : }
974 :
975 : return nsMathMLTokenFrame::Reflow(aPresContext, aDesiredSize,
976 0 : aReflowState, aStatus);
977 : }
978 :
979 : /* virtual */ void
980 0 : nsMathMLmoFrame::MarkIntrinsicWidthsDirty()
981 : {
982 : // if we get this, it may mean that something changed in the text
983 : // content. So blow away everything an re-build the automatic data
984 : // from the parent of our outermost embellished container (we ensure
985 : // that we are the core, not just a sibling of the core)
986 :
987 0 : ProcessTextData();
988 :
989 0 : nsIFrame* target = this;
990 0 : nsEmbellishData embellishData;
991 0 : do {
992 0 : target = target->GetParent();
993 0 : GetEmbellishDataFrom(target, embellishData);
994 : } while (embellishData.coreFrame == this);
995 :
996 : // we have automatic data to update in the children of the target frame
997 : // XXXldb This should really be marking dirty rather than rebuilding
998 : // so that we don't rebuild multiple times for the same change.
999 0 : RebuildAutomaticDataForChildren(target);
1000 :
1001 0 : nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
1002 0 : }
1003 :
1004 : /* virtual */ nscoord
1005 0 : nsMathMLmoFrame::GetIntrinsicWidth(nsRenderingContext *aRenderingContext)
1006 : {
1007 0 : ProcessOperatorData();
1008 : nscoord width;
1009 0 : if (UseMathMLChar()) {
1010 0 : PRUint32 stretchHint = GetStretchHint(mFlags, mPresentationData, true);
1011 : width = mMathMLChar.
1012 : GetMaxWidth(PresContext(), *aRenderingContext,
1013 : stretchHint, mMaxSize,
1014 0 : NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags));
1015 : }
1016 : else {
1017 0 : width = nsMathMLTokenFrame::GetIntrinsicWidth(aRenderingContext);
1018 : }
1019 :
1020 : // leadingSpace and trailingSpace are actually applied to the outermost
1021 : // embellished container but for determining total intrinsic width it should
1022 : // be safe to include it for the core here instead.
1023 0 : width += mEmbellishData.leadingSpace + mEmbellishData.trailingSpace;
1024 :
1025 0 : return width;
1026 : }
1027 :
1028 : NS_IMETHODIMP
1029 0 : nsMathMLmoFrame::AttributeChanged(PRInt32 aNameSpaceID,
1030 : nsIAtom* aAttribute,
1031 : PRInt32 aModType)
1032 : {
1033 : // check if this is an attribute that can affect the embellished hierarchy
1034 : // in a significant way and re-layout the entire hierarchy.
1035 0 : if (nsGkAtoms::accent_ == aAttribute ||
1036 : nsGkAtoms::movablelimits_ == aAttribute) {
1037 :
1038 : // set the target as the parent of our outermost embellished container
1039 : // (we ensure that we are the core, not just a sibling of the core)
1040 0 : nsIFrame* target = this;
1041 0 : nsEmbellishData embellishData;
1042 0 : do {
1043 0 : target = target->GetParent();
1044 0 : GetEmbellishDataFrom(target, embellishData);
1045 : } while (embellishData.coreFrame == this);
1046 :
1047 : // we have automatic data to update in the children of the target frame
1048 0 : return ReLayoutChildren(target);
1049 : }
1050 :
1051 : return nsMathMLTokenFrame::
1052 0 : AttributeChanged(aNameSpaceID, aAttribute, aModType);
1053 : }
1054 :
1055 : // ----------------------
1056 : // No need to track the style context given to our MathML char.
1057 : // the Style System will use these to pass the proper style context to our MathMLChar
1058 : nsStyleContext*
1059 0 : nsMathMLmoFrame::GetAdditionalStyleContext(PRInt32 aIndex) const
1060 : {
1061 0 : switch (aIndex) {
1062 : case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
1063 0 : return mMathMLChar.GetStyleContext();
1064 : default:
1065 0 : return nsnull;
1066 : }
1067 : }
1068 :
1069 : void
1070 0 : nsMathMLmoFrame::SetAdditionalStyleContext(PRInt32 aIndex,
1071 : nsStyleContext* aStyleContext)
1072 : {
1073 0 : switch (aIndex) {
1074 : case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX:
1075 0 : mMathMLChar.SetStyleContext(aStyleContext);
1076 0 : break;
1077 : }
1078 0 : }
|