Back to index

lightning-sunbird  0.9+nobinonly
nsMathMLmsupFrame.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla MathML Project.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * The University Of Queensland.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Roger B. Sidje <rbs@maths.uq.edu.au>
00023  *   David J. Fiddes <D.J.Fiddes@hw.ac.uk>
00024  *   Shyjan Mahamud <mahamud@cs.cmu.edu> (added TeX rendering rules)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsFrame.h"
00042 #include "nsPresContext.h"
00043 #include "nsUnitConversion.h"
00044 #include "nsStyleContext.h"
00045 #include "nsStyleConsts.h"
00046 #include "nsIRenderingContext.h"
00047 #include "nsIFontMetrics.h"
00048 
00049 #include "nsMathMLmsupFrame.h"
00050 
00051 //
00052 // <msup> -- attach a superscript to a base - implementation
00053 //
00054 
00055 nsresult
00056 NS_NewMathMLmsupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00057 {
00058   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00059   if (nsnull == aNewFrame) {
00060     return NS_ERROR_NULL_POINTER;
00061   }
00062   nsMathMLmsupFrame* it = new (aPresShell) nsMathMLmsupFrame;
00063   if (nsnull == it) {
00064     return NS_ERROR_OUT_OF_MEMORY;
00065   }
00066   *aNewFrame = it;
00067   return NS_OK;
00068 }
00069 
00070 nsMathMLmsupFrame::nsMathMLmsupFrame()
00071 {
00072 }
00073 
00074 nsMathMLmsupFrame::~nsMathMLmsupFrame()
00075 {
00076 }
00077 
00078 NS_IMETHODIMP
00079 nsMathMLmsupFrame::TransmitAutomaticData()
00080 {
00081   // if our base is an embellished operator, its flags bubble to us
00082   mPresentationData.baseFrame = mFrames.FirstChild();
00083   GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
00084 
00085   // 1. The REC says:
00086   // The <msup> element increments scriptlevel by 1, and sets displaystyle to
00087   // "false", within superscript, but leaves both attributes unchanged within base.
00088   // 2. The TeXbook (Ch 17. p.141) says the superscript *inherits* the compression,
00089   // so we don't set the compression flag. Our parent will propagate its own.
00090   UpdatePresentationDataFromChildAt(1, -1, 1,
00091     ~NS_MATHML_DISPLAYSTYLE,
00092      NS_MATHML_DISPLAYSTYLE);
00093 
00094   return NS_OK;
00095 }
00096 
00097 NS_IMETHODIMP
00098 nsMathMLmsupFrame::Place(nsIRenderingContext& aRenderingContext,
00099                          PRBool               aPlaceOrigin,
00100                          nsHTMLReflowMetrics& aDesiredSize)
00101 {
00102   // extra spacing after sup/subscript
00103   nscoord scriptSpace = NSFloatPointsToTwips(0.5f); // 0.5pt as in plain TeX
00104 
00105   // check if the superscriptshift attribute is there
00106   nsAutoString value;
00107   nscoord supScriptShift = 0;
00108   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00109                    nsMathMLAtoms::superscriptshift_, value)) {
00110     nsCSSValue cssValue;
00111     if (ParseNumericValue(value, cssValue) && cssValue.IsLengthUnit()) {
00112       supScriptShift = CalcLength(GetPresContext(), mStyleContext, cssValue);
00113     }
00114   }
00115 
00116   return nsMathMLmsupFrame::PlaceSuperScript(GetPresContext(), 
00117                                              aRenderingContext,
00118                                              aPlaceOrigin,
00119                                              aDesiredSize,
00120                                              this,
00121                                              supScriptShift,
00122                                              scriptSpace);
00123 }
00124 
00125 // exported routine that both mover and msup share.
00126 // mover uses this when movablelimits is set.
00127 nsresult
00128 nsMathMLmsupFrame::PlaceSuperScript(nsPresContext*      aPresContext,
00129                                     nsIRenderingContext& aRenderingContext,
00130                                     PRBool               aPlaceOrigin,
00131                                     nsHTMLReflowMetrics& aDesiredSize,
00132                                     nsIFrame*            aFrame,
00133                                     nscoord              aUserSupScriptShift,
00134                                     nscoord              aScriptSpace)
00135 {
00136   // the caller better be a mathml frame
00137   nsIMathMLFrame* mathMLFrame;
00138   aFrame->QueryInterface(NS_GET_IID(nsIMathMLFrame), (void**)&mathMLFrame);
00139   if (!mathMLFrame) return NS_ERROR_INVALID_ARG;
00140 
00141   // force the scriptSpace to be at least 1 pixel 
00142   nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
00143   aScriptSpace = PR_MAX(onePixel, aScriptSpace);
00144 
00146   // Get the children's desired sizes
00147 
00148   nsHTMLReflowMetrics baseSize (nsnull);
00149   nsHTMLReflowMetrics supScriptSize (nsnull);
00150   nsBoundingMetrics bmBase, bmSupScript;
00151   nsIFrame* supScriptFrame = nsnull;
00152   nsIFrame* baseFrame = aFrame->GetFirstChild(nsnull);
00153   if (baseFrame)
00154     supScriptFrame = baseFrame->GetNextSibling();
00155   if (!baseFrame || !supScriptFrame || supScriptFrame->GetNextSibling()) {
00156     // report an error, encourage people to get their markups in order
00157     NS_WARNING("invalid markup");
00158     return NS_STATIC_CAST(nsMathMLContainerFrame*, 
00159                           aFrame)->ReflowError(aRenderingContext, 
00160                                                aDesiredSize);
00161   }
00162   GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
00163   GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
00164 
00165   // get the supdrop from the supscript font
00166   nscoord supDrop;
00167   GetSupDropFromChild(supScriptFrame, supDrop);
00168   // parameter u, Rule 18a, App. G, TeXbook
00169   nscoord minSupScriptShift = bmBase.ascent - supDrop;
00170 
00172   // Place Children 
00173   
00174   // get min supscript shift limit from x-height
00175   // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
00176   nscoord xHeight = 0;
00177   nsCOMPtr<nsIFontMetrics> fm =
00178     aPresContext->GetMetricsFor(baseFrame->GetStyleFont()->mFont);
00179 
00180   fm->GetXHeight (xHeight);
00181   nscoord minShiftFromXHeight = (nscoord) 
00182     (bmSupScript.descent + (1.0f/4.0f) * xHeight);
00183   nscoord italicCorrection;
00184   GetItalicCorrection(bmBase, italicCorrection);
00185 
00186   // supScriptShift{1,2,3}
00187   // = minimum amount to shift the supscript up
00188   // = sup{1,2,3} in TeX
00189   // supScriptShift1 = superscriptshift attribute * x-height
00190   // Note that there are THREE values for supscript shifts depending
00191   // on the current style
00192   nscoord supScriptShift1, supScriptShift2, supScriptShift3;
00193   // Set supScriptShift{1,2,3} default from font
00194   GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
00195 
00196   if (0 < aUserSupScriptShift) {
00197     // the user has set the superscriptshift attribute
00198     float scaler2 = ((float) supScriptShift2) / supScriptShift1;
00199     float scaler3 = ((float) supScriptShift3) / supScriptShift1;
00200     supScriptShift1 = 
00201       PR_MAX(supScriptShift1, aUserSupScriptShift);
00202     supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1);
00203     supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1);
00204   }
00205 
00206   // get sup script shift depending on current script level and display style
00207   // Rule 18c, App. G, TeXbook
00208   nscoord supScriptShift;
00209   nsPresentationData presentationData;
00210   mathMLFrame->GetPresentationData (presentationData);
00211   if ( presentationData.scriptLevel == 0 && 
00212        NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) &&
00213       !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
00214     // Style D in TeXbook
00215     supScriptShift = supScriptShift1;
00216   }
00217   else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
00218     // Style C' in TeXbook = D',T',S',SS'
00219     supScriptShift = supScriptShift3;
00220   }
00221   else {
00222     // everything else = T,S,SS
00223     supScriptShift = supScriptShift2;
00224   }
00225 
00226   // get actual supscriptshift to be used
00227   // Rule 18c, App. G, TeXbook
00228   nscoord actualSupScriptShift = 
00229     PR_MAX(minSupScriptShift,PR_MAX(supScriptShift,minShiftFromXHeight));
00230 
00231   // bounding box
00232   nsBoundingMetrics boundingMetrics;
00233   boundingMetrics.ascent =
00234     PR_MAX(bmBase.ascent, (bmSupScript.ascent + actualSupScriptShift));
00235   boundingMetrics.descent =
00236     PR_MAX(bmBase.descent, (bmSupScript.descent - actualSupScriptShift));
00237 
00238   // leave aScriptSpace after superscript
00239   // add italicCorrection between base and superscript
00240   // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we
00241   // estimate the italic creation ourselves and it isn't the same as TeX 
00242   italicCorrection += onePixel;
00243   boundingMetrics.width = bmBase.width + italicCorrection +
00244                           bmSupScript.width + aScriptSpace;
00245   boundingMetrics.leftBearing = bmBase.leftBearing;
00246   boundingMetrics.rightBearing = bmBase.width + italicCorrection +
00247                                  bmSupScript.rightBearing;
00248   mathMLFrame->SetBoundingMetrics(boundingMetrics);
00249 
00250   // reflow metrics
00251   aDesiredSize.ascent =
00252     PR_MAX(baseSize.ascent, (supScriptSize.ascent + actualSupScriptShift));
00253   aDesiredSize.descent =
00254     PR_MAX(baseSize.descent, (supScriptSize.descent - actualSupScriptShift));
00255   aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
00256   aDesiredSize.width = boundingMetrics.width;
00257   aDesiredSize.mBoundingMetrics = boundingMetrics;
00258 
00259   mathMLFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
00260 
00261   if (aPlaceOrigin) {
00262     nscoord dx, dy;
00263     // now place the base ...
00264     dx = 0; dy = aDesiredSize.ascent - baseSize.ascent;
00265     FinishReflowChild (baseFrame, aPresContext, nsnull, baseSize, dx, dy, 0);
00266     // ... and supscript
00267     dx = bmBase.width + italicCorrection;
00268     dy = aDesiredSize.ascent - (supScriptSize.ascent + actualSupScriptShift);
00269     FinishReflowChild (supScriptFrame, aPresContext, nsnull, supScriptSize, dx, dy, 0);
00270   }
00271 
00272   return NS_OK;
00273 }