WebCore/mathml/RenderMathMLUnderOver.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 
       
    28 #if ENABLE(MATHML)
       
    29 
       
    30 #include "RenderMathMLUnderOver.h"
       
    31 
       
    32 #include "FontSelector.h"
       
    33 #include "MathMLNames.h"
       
    34 
       
    35 namespace WebCore {
       
    36 
       
    37 using namespace MathMLNames;
       
    38     
       
    39 static const double gOverSpacingAdjustment = 0.5;
       
    40     
       
    41 RenderMathMLUnderOver::RenderMathMLUnderOver(Node* expression) 
       
    42     : RenderMathMLBlock(expression) 
       
    43 {
       
    44     Element* element = static_cast<Element*>(expression);
       
    45     // Determine what kind of under/over expression we have by element name
       
    46     
       
    47     if (element->hasLocalName(MathMLNames::munderTag))
       
    48         m_kind = Under;
       
    49     else if (element->hasLocalName(MathMLNames::moverTag))
       
    50         m_kind = Over;
       
    51     else if (element->hasLocalName(MathMLNames::munderoverTag))
       
    52         m_kind = UnderOver;
       
    53     else 
       
    54         m_kind = Under;
       
    55     
       
    56 }
       
    57 
       
    58 void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild)
       
    59 {    
       
    60     RenderMathMLBlock* row = new (renderArena()) RenderMathMLBlock(node());
       
    61     RefPtr<RenderStyle> rowStyle = makeBlockStyle();
       
    62     row->setStyle(rowStyle.release());
       
    63     
       
    64     // look through the children for rendered elements counting the blocks so we know what child
       
    65     // we are adding
       
    66     int blocks = 0;
       
    67     RenderObject* current = this->firstChild();
       
    68     while (current) {
       
    69         blocks++;
       
    70         current = current->nextSibling();
       
    71     }
       
    72     
       
    73     switch (blocks) {
       
    74     case 0:
       
    75         // this is the base so just append it
       
    76         RenderBlock::addChild(row, beforeChild);
       
    77         break;
       
    78     case 1:
       
    79         // the under or over
       
    80         // FIXME: text-align: center does not work
       
    81         row->style()->setTextAlign(CENTER);
       
    82         if (m_kind == Over) {
       
    83             // add the over as first
       
    84             RenderBlock::addChild(row, firstChild());
       
    85         } else {
       
    86             // add the under as last
       
    87             RenderBlock::addChild(row, beforeChild);
       
    88         }
       
    89         break;
       
    90     case 2:
       
    91         // the under or over
       
    92         // FIXME: text-align: center does not work
       
    93         row->style()->setTextAlign(CENTER);
       
    94         if (m_kind == UnderOver) {
       
    95             // add the over as first
       
    96             RenderBlock::addChild(row, firstChild());
       
    97         } else {
       
    98             // we really shouldn't get here as only munderover should have three children
       
    99             RenderBlock::addChild(row, beforeChild);
       
   100         }
       
   101         break;
       
   102     default:
       
   103         // munderover shouldn't have more than three children.  In theory we shouldn't 
       
   104         // get here if the MathML is correctly formed, but that isn't a guarantee.
       
   105         // We will treat this as another under element and they'll get something funky.
       
   106         RenderBlock::addChild(row, beforeChild);
       
   107     }
       
   108     row->addChild(child);    
       
   109 }
       
   110 
       
   111 inline int getOffsetHeight(RenderObject* obj) 
       
   112 {
       
   113     if (obj->isBoxModelObject()) {
       
   114         RenderBoxModelObject* box = toRenderBoxModelObject(obj);
       
   115         return box->offsetHeight();
       
   116     }
       
   117    
       
   118     return 0;
       
   119 }
       
   120 
       
   121 void  RenderMathMLUnderOver::stretchToHeight(int height)
       
   122 {
       
   123 
       
   124     RenderObject* base = firstChild();
       
   125     if (!base)
       
   126         return;
       
   127         
       
   128     // For over or underover, the base is the sibling of the first child
       
   129     if (m_kind != Under) 
       
   130         base = base->nextSibling();
       
   131         
       
   132     if (!base)
       
   133         return;
       
   134         
       
   135     // use the child of the row which is the actual base
       
   136     base = base->firstChild();
       
   137     
       
   138     if (base && base->isRenderMathMLBlock()) {
       
   139         RenderMathMLBlock* block = toRenderMathMLBlock(base);
       
   140         block->stretchToHeight(height);
       
   141         updateBoxModelInfoFromStyle();
       
   142         setNeedsLayoutAndPrefWidthsRecalc();
       
   143         markContainingBlocksForLayout();
       
   144     }
       
   145 }
       
   146 
       
   147 void RenderMathMLUnderOver::layout() 
       
   148 {
       
   149     RenderBlock::layout();
       
   150     RenderObject* over = 0;
       
   151     RenderObject* base = 0;
       
   152     switch (m_kind) {
       
   153     case Over:
       
   154         // We need to calculate the baseline over the over versus the start of the base and 
       
   155         // adjust the placement of the base.
       
   156         over = firstChild();
       
   157         if (over) {
       
   158             // FIXME: descending glyphs intrude into base (e.g. lowercase y over base)
       
   159             // FIXME: bases that ascend higher than the line box intrude into the over
       
   160             int overSpacing = static_cast<int>(gOverSpacingAdjustment * (getOffsetHeight(over) - over->firstChild()->baselinePosition(true)));
       
   161             
       
   162             // base row wrapper
       
   163             base = over->nextSibling();
       
   164             if (base) {
       
   165                 if (overSpacing > 0) 
       
   166                     base->style()->setMarginTop(Length(-overSpacing, Fixed));
       
   167                 else 
       
   168                     base->style()->setMarginTop(Length(0, Fixed));
       
   169             }
       
   170             
       
   171         }
       
   172         break;
       
   173     case Under:
       
   174         // FIXME: Non-ascending glyphs in the under should be moved closer to the base
       
   175 
       
   176         // We need to calculate the baseline of the base versus the start of the under block and
       
   177         // adjust the placement of the under block.
       
   178         
       
   179         // base row wrapper
       
   180         base = firstChild();
       
   181         if (base) {
       
   182             int baseHeight = getOffsetHeight(base);
       
   183             // actual base
       
   184             base = base->firstChild();
       
   185             // FIXME: We need to look at the space between a single maximum height of
       
   186             //        the line boxes and the baseline and squeeze them together
       
   187             int underSpacing = baseHeight - base->baselinePosition(true);
       
   188             
       
   189             // adjust the base's intrusion into the under
       
   190             RenderObject* under = lastChild();
       
   191             if (under && underSpacing > 0)
       
   192                 under->style()->setMarginTop(Length(-underSpacing, Fixed));
       
   193         }
       
   194         break;
       
   195     case UnderOver:
       
   196         // FIXME: Non-descending glyphs in the over should be moved closer to the base
       
   197         // FIXME: Non-ascending glyphs in the under should be moved closer to the base
       
   198         
       
   199         // We need to calculate the baseline of the over versus the start of the base and 
       
   200         // adjust the placement of the base.
       
   201         
       
   202         over = firstChild();
       
   203         if (over) {
       
   204             // FIXME: descending glyphs intrude into base (e.g. lowercase y over base)
       
   205             // FIXME: bases that ascend higher than the line box intrude into the over
       
   206             int overSpacing = static_cast<int>(gOverSpacingAdjustment * (getOffsetHeight(over) - over->firstChild()->baselinePosition(true)));
       
   207             
       
   208             // base row wrapper
       
   209             base = over->nextSibling();
       
   210             
       
   211             if (base) {
       
   212                 if (overSpacing > 0)
       
   213                     base->style()->setMarginTop(Length(-overSpacing, Fixed));
       
   214                 
       
   215                 // We need to calculate the baseline of the base versus the start of the under block and
       
   216                 // adjust the placement of the under block.
       
   217                 
       
   218                 int baseHeight = getOffsetHeight(base);
       
   219                 // actual base
       
   220                 base = base->firstChild();
       
   221                 // FIXME: We need to look at the space between a single maximum height of
       
   222                 //        the line boxes and the baseline and squeeze them together
       
   223                 int underSpacing = baseHeight - base->baselinePosition(true);
       
   224                 
       
   225                 RenderObject* under = lastChild();
       
   226                 if (under && under->firstChild()->isRenderInline() && underSpacing > 0)
       
   227                     under->style()->setMarginTop(Length(-underSpacing, Fixed));
       
   228                 
       
   229             }
       
   230         }
       
   231         break;
       
   232     }
       
   233     setNeedsLayoutAndPrefWidthsRecalc();
       
   234     RenderBlock::layout();
       
   235 }
       
   236 
       
   237 int RenderMathMLUnderOver::baselinePosition(bool firstLine, bool isRootLineBox) const
       
   238 {
       
   239     int baseline = 0;
       
   240     RenderObject* current = 0;
       
   241     switch (m_kind) {
       
   242     case UnderOver:
       
   243     case Over:
       
   244         current = firstChild();
       
   245         baseline += getOffsetHeight(current);
       
   246         current = current->nextSibling();
       
   247         if (current) {
       
   248             // actual base
       
   249             RenderObject* base = current->firstChild();
       
   250             baseline += base->baselinePosition(firstLine, isRootLineBox);
       
   251             // added the negative top margin
       
   252             baseline += current->style()->marginTop().value();
       
   253             // FIXME: Where is the extra 2-3px adjusted for zoom coming from?
       
   254             float zoomFactor = style()->effectiveZoom();
       
   255             baseline += static_cast<int>((zoomFactor > 1.25 ? 2 : 3) * zoomFactor);
       
   256         }
       
   257         break;
       
   258     case Under:
       
   259         current = firstChild();
       
   260         if (current) {
       
   261             RenderObject* base = current->firstChild();
       
   262             baseline += base->baselinePosition(true);
       
   263             // FIXME: Where is the extra 2-3px adjusted for zoom coming from?
       
   264             float zoomFactor = style()->effectiveZoom();
       
   265             baseline += static_cast<int>((zoomFactor > 1.25 ? 2 : 3) * zoomFactor);
       
   266         }
       
   267     }
       
   268     return baseline;
       
   269 }
       
   270 
       
   271 
       
   272 int RenderMathMLUnderOver::nonOperatorHeight() const 
       
   273 {
       
   274     return 0;
       
   275 }
       
   276 
       
   277 }
       
   278 
       
   279 
       
   280 #endif // ENABLE(MATHML)