Back to index

lightning-sunbird  0.9+nobinonly
nsMathMLmsubFrame.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 
00041 #include "nsCOMPtr.h"
00042 #include "nsFrame.h"
00043 #include "nsPresContext.h"
00044 #include "nsUnitConversion.h"
00045 #include "nsStyleContext.h"
00046 #include "nsStyleConsts.h"
00047 #include "nsIRenderingContext.h"
00048 #include "nsIFontMetrics.h"
00049 
00050 #include "nsMathMLmsubFrame.h"
00051 
00052 //
00053 // <msub> -- attach a subscript to a base - implementation
00054 //
00055 
00056 nsresult
00057 NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00058 {
00059   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00060   if (nsnull == aNewFrame) {
00061     return NS_ERROR_NULL_POINTER;
00062   }
00063   nsMathMLmsubFrame* it = new (aPresShell) nsMathMLmsubFrame;
00064   if (nsnull == it) {
00065     return NS_ERROR_OUT_OF_MEMORY;
00066   }
00067   *aNewFrame = it;
00068   return NS_OK;
00069 }
00070 
00071 nsMathMLmsubFrame::nsMathMLmsubFrame()
00072 {
00073 }
00074 
00075 nsMathMLmsubFrame::~nsMathMLmsubFrame()
00076 {
00077 }
00078 
00079 NS_IMETHODIMP
00080 nsMathMLmsubFrame::TransmitAutomaticData()
00081 {
00082   // if our base is an embellished operator, let its state bubble to us
00083   mPresentationData.baseFrame = mFrames.FirstChild();
00084   GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
00085 
00086   // 1. The REC says:
00087   // The <msub> element increments scriptlevel by 1, and sets displaystyle to
00088   // "false", within subscript, but leaves both attributes unchanged within base.
00089   // 2. The TeXbook (Ch 17. p.141) says the subscript is compressed
00090   UpdatePresentationDataFromChildAt(1, -1, 1,
00091     ~NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED,
00092      NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED);
00093 
00094   return NS_OK;
00095 }
00096 
00097 NS_IMETHODIMP
00098 nsMathMLmsubFrame::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 subscriptshift attribute is there
00106   nscoord subScriptShift = 0;
00107   nsAutoString value;
00108   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttribute(mContent, mPresentationData.mstyle,
00109                    nsMathMLAtoms::subscriptshift_, value)) {
00110     nsCSSValue cssValue;
00111     if (ParseNumericValue(value, cssValue) && cssValue.IsLengthUnit()) {
00112       subScriptShift = CalcLength(GetPresContext(), mStyleContext, cssValue);
00113     }
00114   }
00115 
00116   return nsMathMLmsubFrame::PlaceSubScript(GetPresContext(), 
00117                                            aRenderingContext,
00118                                            aPlaceOrigin,
00119                                            aDesiredSize,
00120                                            this,
00121                                            subScriptShift,
00122                                            scriptSpace);
00123 }
00124 
00125 // exported routine that both munder and msub share.
00126 // munder uses this when movablelimits is set.
00127 nsresult
00128 nsMathMLmsubFrame::PlaceSubScript (nsPresContext*      aPresContext,
00129                                    nsIRenderingContext& aRenderingContext,
00130                                    PRBool               aPlaceOrigin,
00131                                    nsHTMLReflowMetrics& aDesiredSize,
00132                                    nsIFrame*            aFrame,
00133                                    nscoord              aUserSubScriptShift,
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 atleast 1 pixel 
00142   aScriptSpace = PR_MAX(aPresContext->IntScaledPixelsToTwips(1), aScriptSpace);
00143 
00145   // Get the children's desired sizes
00146 
00147   nsBoundingMetrics bmBase, bmSubScript;
00148   nsHTMLReflowMetrics baseSize(nsnull);
00149   nsHTMLReflowMetrics subScriptSize(nsnull);
00150   nsIFrame* baseFrame = aFrame->GetFirstChild(nsnull);
00151   nsIFrame* subScriptFrame = nsnull;
00152   if (baseFrame)
00153     subScriptFrame = baseFrame->GetNextSibling();
00154   if (!baseFrame || !subScriptFrame || subScriptFrame->GetNextSibling()) {
00155     // report an error, encourage people to get their markups in order
00156     NS_WARNING("invalid markup");
00157     return NS_STATIC_CAST(nsMathMLContainerFrame*, 
00158                           aFrame)->ReflowError(aRenderingContext, 
00159                                                aDesiredSize);
00160   }
00161   GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
00162   GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
00163 
00164   // get the subdrop from the subscript font
00165   nscoord subDrop;
00166   GetSubDropFromChild(subScriptFrame, subDrop);
00167   // parameter v, Rule 18a, App. G, TeXbook
00168   nscoord minSubScriptShift = bmBase.descent + subDrop;
00169 
00171   // Place Children
00172   
00173   // get min subscript shift limit from x-height
00174   // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
00175   nscoord xHeight = 0;
00176   nsCOMPtr<nsIFontMetrics> fm =
00177     aPresContext->GetMetricsFor(baseFrame->GetStyleFont()->mFont);
00178 
00179   fm->GetXHeight (xHeight);
00180   nscoord minShiftFromXHeight = (nscoord) 
00181     (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
00182 
00183   // subScriptShift
00184   // = minimum amount to shift the subscript down set by user or from the font
00185   // = sub1 in TeX
00186   // = subscriptshift attribute * x-height
00187   nscoord subScriptShift, dummy;
00188   // get subScriptShift default from font
00189   GetSubScriptShifts (fm, subScriptShift, dummy);
00190 
00191   subScriptShift = 
00192     PR_MAX(subScriptShift, aUserSubScriptShift);
00193 
00194   // get actual subscriptshift to be used
00195   // Rule 18b, App. G, TeXbook
00196   nscoord actualSubScriptShift = 
00197     PR_MAX(minSubScriptShift,PR_MAX(subScriptShift,minShiftFromXHeight));
00198   // get bounding box for base + subscript
00199   nsBoundingMetrics boundingMetrics;
00200   boundingMetrics.ascent = 
00201     PR_MAX(bmBase.ascent, bmSubScript.ascent - actualSubScriptShift);
00202   boundingMetrics.descent = 
00203     PR_MAX(bmBase.descent, bmSubScript.descent + actualSubScriptShift);
00204 
00205   // add aScriptSpace to the subscript's width
00206   boundingMetrics.width = bmBase.width + bmSubScript.width + aScriptSpace;
00207   boundingMetrics.leftBearing = bmBase.leftBearing;
00208   boundingMetrics.rightBearing = PR_MAX(bmBase.rightBearing, bmBase.width +
00209     PR_MAX(bmSubScript.width + aScriptSpace, bmSubScript.rightBearing));
00210   mathMLFrame->SetBoundingMetrics (boundingMetrics);
00211 
00212   // reflow metrics
00213   aDesiredSize.ascent = 
00214     PR_MAX(baseSize.ascent, subScriptSize.ascent - actualSubScriptShift);
00215   aDesiredSize.descent = 
00216     PR_MAX(baseSize.descent, subScriptSize.descent + actualSubScriptShift);
00217   aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
00218   aDesiredSize.width = boundingMetrics.width;
00219   aDesiredSize.mBoundingMetrics = boundingMetrics;
00220 
00221   mathMLFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
00222 
00223   if (aPlaceOrigin) {
00224     nscoord dx, dy;
00225     // now place the base ...
00226     dx = 0; dy = aDesiredSize.ascent - baseSize.ascent;
00227     FinishReflowChild (baseFrame, aPresContext, nsnull, baseSize, dx, dy, 0);
00228     // ... and subscript
00229     dx = bmBase.width; 
00230     dy = aDesiredSize.ascent - (subScriptSize.ascent - actualSubScriptShift);
00231     FinishReflowChild (subScriptFrame, aPresContext, nsnull, subScriptSize, dx, dy, 0);
00232   }
00233 
00234   return NS_OK;
00235 }