LCOV - code coverage report
Current view: directory - layout/mathml - nsMathMLTokenFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 160 0 0.0 %
Date: 2012-06-02 Functions: 18 0 0.0 %

       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                 :  *   Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
      25                 :  *   Frederic Wang <fred.wang@free.fr>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsCOMPtr.h"
      42                 : #include "nsFrame.h"
      43                 : #include "nsPresContext.h"
      44                 : #include "nsStyleContext.h"
      45                 : #include "nsStyleConsts.h"
      46                 : #include "nsContentUtils.h"
      47                 : #include "nsCSSFrameConstructor.h"
      48                 : #include "nsMathMLTokenFrame.h"
      49                 : 
      50                 : nsIFrame*
      51               0 : NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      52                 : {
      53               0 :   return new (aPresShell) nsMathMLTokenFrame(aContext);
      54                 : }
      55                 : 
      56               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
      57                 : 
      58               0 : nsMathMLTokenFrame::~nsMathMLTokenFrame()
      59                 : {
      60               0 : }
      61                 : 
      62                 : NS_IMETHODIMP
      63               0 : nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
      64                 : {
      65                 :   // let the base class get the default from our parent
      66               0 :   nsMathMLContainerFrame::InheritAutomaticData(aParent);
      67                 : 
      68               0 :   if (mContent->Tag() != nsGkAtoms::mspace_) {
      69                 :     // see if the directionality attribute is there
      70               0 :     nsMathMLFrame::FindAttrDirectionality(mContent, mPresentationData);
      71                 :   }
      72                 : 
      73               0 :   ProcessTextData();
      74                 : 
      75               0 :   return NS_OK;
      76                 : }
      77                 : 
      78                 : eMathMLFrameType
      79               0 : nsMathMLTokenFrame::GetMathMLFrameType()
      80                 : {
      81                 :   // treat everything other than <mi> as ordinary...
      82               0 :   if (mContent->Tag() != nsGkAtoms::mi_) {
      83               0 :     return eMathMLFrameType_Ordinary;
      84                 :   }
      85                 : 
      86                 :   // for <mi>, distinguish between italic and upright...
      87               0 :   nsAutoString style;
      88                 :   // mathvariant overrides fontstyle
      89                 :   // http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.deprecatt
      90                 :   mContent->GetAttr(kNameSpaceID_None,
      91               0 :                     nsGkAtoms::_moz_math_fontstyle_, style) ||
      92                 :     GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::mathvariant_,
      93               0 :                  style) ||
      94                 :     GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::fontstyle_,
      95               0 :                  style);
      96                 : 
      97               0 :   if (style.EqualsLiteral("italic") || style.EqualsLiteral("bold-italic") ||
      98               0 :       style.EqualsLiteral("script") || style.EqualsLiteral("bold-script") ||
      99               0 :       style.EqualsLiteral("sans-serif-italic") ||
     100               0 :       style.EqualsLiteral("sans-serif-bold-italic")) {
     101               0 :     return eMathMLFrameType_ItalicIdentifier;
     102                 :   }
     103               0 :   else if(style.EqualsLiteral("invariant")) {
     104               0 :     nsAutoString data;
     105               0 :     nsContentUtils::GetNodeTextContent(mContent, false, data);
     106               0 :     eMATHVARIANT variant = nsMathMLOperators::LookupInvariantChar(data);
     107                 : 
     108               0 :     switch (variant) {
     109                 :     case eMATHVARIANT_italic:
     110                 :     case eMATHVARIANT_bold_italic:
     111                 :     case eMATHVARIANT_script:
     112                 :     case eMATHVARIANT_bold_script:
     113                 :     case eMATHVARIANT_sans_serif_italic:
     114                 :     case eMATHVARIANT_sans_serif_bold_italic:
     115               0 :       return eMathMLFrameType_ItalicIdentifier;
     116                 :     default:
     117                 :       ; // fall through to upright
     118                 :     }
     119                 :   }
     120               0 :   return eMathMLFrameType_UprightIdentifier;
     121                 : }
     122                 : 
     123                 : static void
     124               0 : CompressWhitespace(nsIContent* aContent)
     125                 : {
     126               0 :   PRUint32 numKids = aContent->GetChildCount();
     127               0 :   for (PRUint32 kid = 0; kid < numKids; kid++) {
     128               0 :     nsIContent* cont = aContent->GetChildAt(kid);
     129               0 :     if (cont && cont->IsNodeOfType(nsINode::eTEXT)) {
     130               0 :       nsAutoString text;
     131               0 :       cont->AppendTextTo(text);
     132               0 :       text.CompressWhitespace();
     133               0 :       cont->SetText(text, false); // not meant to be used if notify is needed
     134                 :     }
     135                 :   }
     136               0 : }
     137                 : 
     138                 : NS_IMETHODIMP
     139               0 : nsMathMLTokenFrame::Init(nsIContent*      aContent,
     140                 :                          nsIFrame*        aParent,
     141                 :                          nsIFrame*        aPrevInFlow)
     142                 : {
     143                 :   // leading and trailing whitespace doesn't count -- bug 15402
     144                 :   // brute force removal for people who do <mi> a </mi> instead of <mi>a</mi>
     145                 :   // XXX the best fix is to skip these in nsTextFrame
     146               0 :   CompressWhitespace(aContent);
     147                 : 
     148                 :   // let the base class do its Init()
     149               0 :   return nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
     150                 : }
     151                 : 
     152                 : NS_IMETHODIMP
     153               0 : nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
     154                 :                                         nsFrameList&    aChildList)
     155                 : {
     156                 :   // First, let the base class do its work
     157               0 :   nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
     158               0 :   if (NS_FAILED(rv))
     159               0 :     return rv;
     160                 : 
     161               0 :   SetQuotes(false);
     162               0 :   ProcessTextData();
     163               0 :   return rv;
     164                 : }
     165                 : 
     166                 : nsresult
     167               0 : nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
     168                 :                            nsHTMLReflowMetrics&     aDesiredSize,
     169                 :                            const nsHTMLReflowState& aReflowState,
     170                 :                            nsReflowStatus&          aStatus)
     171                 : {
     172               0 :   nsresult rv = NS_OK;
     173                 : 
     174                 :   // initializations needed for empty markup like <mtag></mtag>
     175               0 :   aDesiredSize.width = aDesiredSize.height = 0;
     176               0 :   aDesiredSize.ascent = 0;
     177               0 :   aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
     178                 : 
     179               0 :   nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
     180               0 :   nsIFrame* childFrame = GetFirstPrincipalChild();
     181               0 :   while (childFrame) {
     182                 :     // ask our children to compute their bounding metrics
     183                 :     nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags
     184               0 :                                          | NS_REFLOW_CALC_BOUNDING_METRICS);
     185                 :     nsHTMLReflowState childReflowState(aPresContext, aReflowState,
     186               0 :                                        childFrame, availSize);
     187                 :     rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
     188               0 :                      childReflowState, aStatus);
     189                 :     //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
     190               0 :     if (NS_FAILED(rv)) {
     191                 :       // Call DidReflow() for the child frames we successfully did reflow.
     192               0 :       DidReflowChildren(GetFirstPrincipalChild(), childFrame);
     193               0 :       return rv;
     194                 :     }
     195                 : 
     196                 :     SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
     197               0 :                                     childDesiredSize.mBoundingMetrics);
     198                 : 
     199               0 :     childFrame = childFrame->GetNextSibling();
     200                 :   }
     201                 : 
     202                 : 
     203                 :   // place and size children
     204               0 :   FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
     205                 : 
     206               0 :   aStatus = NS_FRAME_COMPLETE;
     207               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
     208               0 :   return NS_OK;
     209                 : }
     210                 : 
     211                 : // For token elements, mBoundingMetrics is computed at the ReflowToken
     212                 : // pass, it is not computed here because our children may be text frames
     213                 : // that do not implement the GetBoundingMetrics() interface.
     214                 : /* virtual */ nsresult
     215               0 : nsMathMLTokenFrame::Place(nsRenderingContext& aRenderingContext,
     216                 :                           bool                 aPlaceOrigin,
     217                 :                           nsHTMLReflowMetrics& aDesiredSize)
     218                 : {
     219               0 :   mBoundingMetrics = nsBoundingMetrics();
     220               0 :   for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
     221                 :        childFrame = childFrame->GetNextSibling()) {
     222               0 :     nsHTMLReflowMetrics childSize;
     223                 :     GetReflowAndBoundingMetricsFor(childFrame, childSize,
     224               0 :                                    childSize.mBoundingMetrics, nsnull);
     225                 :     // compute and cache the bounding metrics
     226               0 :     mBoundingMetrics += childSize.mBoundingMetrics;
     227                 :   }
     228                 : 
     229               0 :   nsRefPtr<nsFontMetrics> fm;
     230               0 :   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
     231               0 :   nscoord ascent = fm->MaxAscent();
     232               0 :   nscoord descent = fm->MaxDescent();
     233                 : 
     234               0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     235               0 :   aDesiredSize.width = mBoundingMetrics.width;
     236               0 :   aDesiredSize.ascent = NS_MAX(mBoundingMetrics.ascent, ascent);
     237                 :   aDesiredSize.height = aDesiredSize.ascent +
     238               0 :                         NS_MAX(mBoundingMetrics.descent, descent);
     239                 : 
     240               0 :   if (aPlaceOrigin) {
     241               0 :     nscoord dy, dx = 0;
     242               0 :     for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
     243                 :          childFrame = childFrame->GetNextSibling()) {
     244               0 :       nsHTMLReflowMetrics childSize;
     245                 :       GetReflowAndBoundingMetricsFor(childFrame, childSize,
     246               0 :                                      childSize.mBoundingMetrics);
     247                 : 
     248                 :       // place and size the child; (dx,0) makes the caret happy - bug 188146
     249               0 :       dy = childSize.height == 0 ? 0 : aDesiredSize.ascent - childSize.ascent;
     250               0 :       FinishReflowChild(childFrame, PresContext(), nsnull, childSize, dx, dy, 0);
     251               0 :       dx += childSize.width;
     252                 :     }
     253                 :   }
     254                 : 
     255               0 :   SetReference(nsPoint(0, aDesiredSize.ascent));
     256                 : 
     257               0 :   return NS_OK;
     258                 : }
     259                 : 
     260                 : /* virtual */ void
     261               0 : nsMathMLTokenFrame::MarkIntrinsicWidthsDirty()
     262                 : {
     263                 :   // this could be called due to changes in the nsTextFrame beneath us
     264                 :   // when something changed in the text content. So re-process our text
     265               0 :   ProcessTextData();
     266                 : 
     267               0 :   nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
     268               0 : }
     269                 : 
     270                 : NS_IMETHODIMP
     271               0 : nsMathMLTokenFrame::AttributeChanged(PRInt32         aNameSpaceID,
     272                 :                                      nsIAtom*        aAttribute,
     273                 :                                      PRInt32         aModType)
     274                 : {
     275               0 :   if (nsGkAtoms::lquote_ == aAttribute ||
     276                 :       nsGkAtoms::rquote_ == aAttribute) {
     277               0 :     SetQuotes(true);
     278                 :   }
     279                 : 
     280                 :   return nsMathMLContainerFrame::
     281               0 :          AttributeChanged(aNameSpaceID, aAttribute, aModType);
     282                 : }
     283                 : 
     284                 : void
     285               0 : nsMathMLTokenFrame::ProcessTextData()
     286                 : {
     287                 :   // see if the style changes from normal to italic or vice-versa
     288               0 :   if (!SetTextStyle())
     289               0 :     return;
     290                 : 
     291                 :   // explicitly request a re-resolve to pick up the change of style
     292                 :   PresContext()->PresShell()->FrameConstructor()->
     293               0 :     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
     294                 : }
     295                 : 
     296                 : ///////////////////////////////////////////////////////////////////////////
     297                 : // For <mi>, if the content is not a single character, turn the font to
     298                 : // normal (this function will also query attributes from the mstyle hierarchy)
     299                 : // Returns true if there is a style change.
     300                 : //
     301                 : // http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.commatt
     302                 : //
     303                 : //  "It is important to note that only certain combinations of
     304                 : //   character data and mathvariant attribute values make sense.
     305                 : //   ...
     306                 : //   By design, the only cases that have an unambiguous
     307                 : //   interpretation are exactly the ones that correspond to SMP Math
     308                 : //   Alphanumeric Symbol characters, which are enumerated in Section
     309                 : //   6.2.3 Mathematical Alphanumeric Symbols Characters. In all other
     310                 : //   cases, it is suggested that renderers ignore the value of the
     311                 : //   mathvariant attribute if it is present."
     312                 : //
     313                 : // There are no corresponding characters for mathvariant=normal, suggesting
     314                 : // that this value should be ignored, but this (from the same section of
     315                 : // Chapter 3) implies that font-style should not be inherited, but set to
     316                 : // normal for mathvariant=normal:
     317                 : //
     318                 : //  "In particular, inheritance of the mathvariant attribute does not follow
     319                 : //   the CSS model. The default value for this attribute is "normal"
     320                 : //   (non-slanted) for all tokens except mi. ... (The deprecated fontslant
     321                 : //   attribute also behaves this way.)"
     322                 : 
     323                 : bool
     324               0 : nsMathMLTokenFrame::SetTextStyle()
     325                 : {
     326               0 :   if (mContent->Tag() != nsGkAtoms::mi_)
     327               0 :     return false;
     328                 : 
     329               0 :   if (!mFrames.FirstChild())
     330               0 :     return false;
     331                 : 
     332                 :   // Get the text content that we enclose and its length
     333               0 :   nsAutoString data;
     334               0 :   nsContentUtils::GetNodeTextContent(mContent, false, data);
     335               0 :   PRInt32 length = data.Length();
     336               0 :   if (!length)
     337               0 :     return false;
     338                 : 
     339               0 :   nsAutoString fontstyle;
     340                 :   bool isSingleCharacter =
     341                 :     length == 1 ||
     342               0 :     (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
     343               0 :   if (isSingleCharacter &&
     344               0 :       nsMathMLOperators::LookupInvariantChar(data) != eMATHVARIANT_NONE) {
     345                 :     // bug 65951 - a non-stylable character has its own intrinsic appearance
     346               0 :     fontstyle.AssignLiteral("invariant");
     347                 :   }
     348                 :   else {
     349                 :     // Attributes override the default behavior.
     350               0 :     nsAutoString value;
     351               0 :     if (!(GetAttribute(mContent, mPresentationData.mstyle,
     352               0 :                        nsGkAtoms::mathvariant_, value) ||
     353                 :           GetAttribute(mContent, mPresentationData.mstyle,
     354               0 :                        nsGkAtoms::fontstyle_, value))) {
     355               0 :       if (!isSingleCharacter) {
     356               0 :         fontstyle.AssignLiteral("normal");
     357                 :       }
     358               0 :       else if (length == 1 && // BMP
     359                 :                !nsMathMLOperators::
     360               0 :                 TransformVariantChar(data[0], eMATHVARIANT_italic).
     361               0 :                 Equals(data)) {
     362                 :         // Transformation exists.  Try to make the BMP character look like the
     363                 :         // styled character using the style system until bug 114365 is resolved.
     364               0 :         fontstyle.AssignLiteral("italic");
     365                 :       }
     366                 :       // else single character but there is no corresponding Math Alphanumeric
     367                 :       // Symbol character: "ignore the value of the [default] mathvariant
     368                 :       // attribute".
     369                 :     }
     370                 :   }
     371                 : 
     372                 :   // set the _moz-math-font-style attribute without notifying that we want a reflow
     373               0 :   if (fontstyle.IsEmpty()) {
     374               0 :     if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_)) {
     375                 :       mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
     376               0 :                           false);
     377               0 :       return true;
     378                 :     }
     379                 :   }
     380               0 :   else if (!mContent->AttrValueIs(kNameSpaceID_None,
     381                 :                                   nsGkAtoms::_moz_math_fontstyle_,
     382               0 :                                   fontstyle, eCaseMatters)) {
     383                 :     mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
     384               0 :                       fontstyle, false);
     385               0 :     return true;
     386                 :   }
     387                 : 
     388               0 :   return false;
     389                 : }
     390                 : 
     391                 : ///////////////////////////////////////////////////////////////////////////
     392                 : // For <ms>, it is assumed that the mathml.css file contains two rules:
     393                 : // ms:before { content: open-quote; }
     394                 : // ms:after { content: close-quote; }
     395                 : // With these two rules, the frame construction code will
     396                 : // create inline frames that contain text frames which themselves
     397                 : // contain the text content of the quotes.
     398                 : // So the main idea in this code is to see if there are lquote and 
     399                 : // rquote attributes. If these are there, we ovewrite the default
     400                 : // quotes in the text frames.
     401                 : // XXX this is somewhat bogus, we probably should map lquote and rquote
     402                 : // to 'content' style rules
     403                 : //
     404                 : // But what if the mathml.css file wasn't loaded? 
     405                 : // We also check that we are not relying on null pointers...
     406                 : 
     407                 : static void
     408               0 : SetQuote(nsIFrame* aFrame, nsString& aValue, bool aNotify)
     409                 : {
     410               0 :   if (!aFrame)
     411               0 :     return;
     412                 : 
     413               0 :   nsIFrame* textFrame = aFrame->GetFirstPrincipalChild();
     414               0 :   if (!textFrame)
     415               0 :     return;
     416                 : 
     417               0 :   nsIContent* quoteContent = textFrame->GetContent();
     418               0 :   if (!quoteContent->IsNodeOfType(nsINode::eTEXT))
     419               0 :     return;
     420                 : 
     421               0 :   quoteContent->SetText(aValue, aNotify);
     422                 : }
     423                 : 
     424                 : void
     425               0 : nsMathMLTokenFrame::SetQuotes(bool aNotify)
     426                 : {
     427               0 :   if (mContent->Tag() != nsGkAtoms::ms_)
     428               0 :     return;
     429                 : 
     430               0 :   nsAutoString value;
     431                 :   // lquote
     432               0 :   if (GetAttribute(mContent, mPresentationData.mstyle,
     433               0 :                    nsGkAtoms::lquote_, value)) {
     434               0 :     SetQuote(nsLayoutUtils::GetBeforeFrame(this), value, aNotify);
     435                 :   }
     436                 :   // rquote
     437               0 :   if (GetAttribute(mContent, mPresentationData.mstyle,
     438               0 :                    nsGkAtoms::rquote_, value)) {
     439               0 :     SetQuote(nsLayoutUtils::GetAfterFrame(this), value, aNotify);
     440                 :   }
     441                 : }

Generated by: LCOV version 1.7