Home | History | Annotate | Download | only in mathml
      1 /*
      2  * Copyright (C) 2009 Alex Milowski (alex (at) milowski.com). All rights reserved.
      3  * Copyright (C) 2010 Franois Sausset (sausset (at) gmail.com). All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 
     29 #if ENABLE(MATHML)
     30 
     31 #include "RenderMathMLSquareRoot.h"
     32 
     33 #include "GraphicsContext.h"
     34 #include "MathMLNames.h"
     35 #include "PaintInfo.h"
     36 #include "Path.h"
     37 
     38 namespace WebCore {
     39 
     40 using namespace MathMLNames;
     41 
     42 // Bottom padding of the radical (px)
     43 const int gRadicalBasePad = 3;
     44 // Threshold above which the radical shape is modified to look nice with big bases (%)
     45 const float gThresholdBaseHeight = 1.5f;
     46 // Radical width (%)
     47 const float gRadicalWidth = 0.75f;
     48 // Horizontal position of the bottom point of the radical (%)
     49 const float gRadicalBottomPointXPos= 0.5f;
     50 // Horizontal position of the top left point of the radical (%)
     51 const float gRadicalTopLeftPointXPos = 0.2f;
     52 // Vertical position of the top left point of the radical (%)
     53 const float gRadicalTopLeftPointYPos = 0.5f;
     54 // Vertical shift of the left end point of the radical (%)
     55 const float gRadicalLeftEndYShift = 0.05f;
     56 // Additional bottom root padding (%)
     57 const float gRootBottomPadding = 0.2f;
     58 
     59 // Radical line thickness (%)
     60 const float gRadicalLineThickness = 0.02f;
     61 // Radical thick line thickness (%)
     62 const float gRadicalThickLineThickness = 0.1f;
     63 
     64 RenderMathMLSquareRoot::RenderMathMLSquareRoot(Node *expression)
     65     : RenderMathMLBlock(expression)
     66 {
     67 }
     68 
     69 void RenderMathMLSquareRoot::paint(PaintInfo& info, int tx, int ty)
     70 {
     71     RenderMathMLBlock::paint(info, tx, ty);
     72 
     73     if (info.context->paintingDisabled())
     74         return;
     75 
     76     tx += x();
     77     ty += y();
     78 
     79     int maxHeight = 0;
     80     int width = 0;
     81     RenderObject* current = firstChild();
     82     while (current) {
     83         if (current->isBoxModelObject()) {
     84 
     85             RenderBoxModelObject* box = toRenderBoxModelObject(current);
     86 
     87             // Check to see if this box has a larger height
     88             if (box->offsetHeight() > maxHeight)
     89                 maxHeight = box->offsetHeight();
     90             width += box->offsetWidth();
     91         }
     92         current = current->nextSibling();
     93     }
     94     // default to the font size in pixels if we're empty
     95     if (!maxHeight)
     96         maxHeight = style()->fontSize();
     97 
     98     int frontWidth = static_cast<int>(style()->fontSize() * gRadicalWidth);
     99     int topStartShift = 0;
    100     // Base height above which the shape of the root changes
    101     int thresholdHeight = static_cast<int>(gThresholdBaseHeight * style()->fontSize());
    102 
    103     if (maxHeight > thresholdHeight && thresholdHeight) {
    104         float shift = (maxHeight - thresholdHeight) / static_cast<float>(thresholdHeight);
    105         if (shift > 1.)
    106             shift = 1.0f;
    107         topStartShift = static_cast<int>(gRadicalBottomPointXPos * frontWidth * shift);
    108     }
    109 
    110     width += topStartShift;
    111 
    112     FloatPoint topStart(tx + frontWidth - topStartShift, ty);
    113     FloatPoint bottomLeft(tx + frontWidth * gRadicalBottomPointXPos , ty + maxHeight + gRadicalBasePad);
    114     FloatPoint topLeft(tx + frontWidth * gRadicalTopLeftPointXPos , ty + gRadicalTopLeftPointYPos * maxHeight);
    115     FloatPoint leftEnd(tx , topLeft.y() + gRadicalLeftEndYShift * style()->fontSize());
    116 
    117     info.context->save();
    118 
    119     info.context->setStrokeThickness(gRadicalLineThickness * style()->fontSize());
    120     info.context->setStrokeStyle(SolidStroke);
    121     info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
    122     info.context->setLineJoin(MiterJoin);
    123     info.context->setMiterLimit(style()->fontSize());
    124 
    125     Path root;
    126 
    127     root.moveTo(FloatPoint(topStart.x() + width , ty));
    128     // draw top
    129     root.addLineTo(topStart);
    130     // draw from top left corner to bottom point of radical
    131     root.addLineTo(bottomLeft);
    132     // draw from bottom point to top of left part of radical base "pocket"
    133     root.addLineTo(topLeft);
    134     // draw to end
    135     root.addLineTo(leftEnd);
    136 
    137     info.context->strokePath(root);
    138 
    139     info.context->save();
    140 
    141     // Build a mask to draw the thick part of the root.
    142     Path mask;
    143 
    144     mask.moveTo(topStart);
    145     mask.addLineTo(bottomLeft);
    146     mask.addLineTo(topLeft);
    147     mask.addLineTo(FloatPoint(2 * topLeft.x() - leftEnd.x(), 2 * topLeft.y() - leftEnd.y()));
    148 
    149     info.context->clip(mask);
    150 
    151     // Draw the thick part of the root.
    152     info.context->setStrokeThickness(gRadicalThickLineThickness * style()->fontSize());
    153     info.context->setLineCap(SquareCap);
    154 
    155     Path line;
    156     line.moveTo(bottomLeft);
    157     line.addLineTo(topLeft);
    158 
    159     info.context->strokePath(line);
    160 
    161     info.context->restore();
    162 
    163     info.context->restore();
    164 }
    165 
    166 void RenderMathMLSquareRoot::layout()
    167 {
    168     int maxHeight = 0;
    169 
    170     RenderObject* current = firstChild();
    171     while (current) {
    172         if (current->isBoxModelObject()) {
    173             RenderBoxModelObject* box = toRenderBoxModelObject(current);
    174 
    175             if (box->offsetHeight() > maxHeight)
    176                 maxHeight = box->offsetHeight();
    177 
    178             box->style()->setVerticalAlign(BASELINE);
    179         }
    180         current = current->nextSibling();
    181     }
    182 
    183     if (!maxHeight)
    184         maxHeight = style()->fontSize();
    185 
    186 
    187     if (maxHeight > static_cast<int>(gThresholdBaseHeight * style()->fontSize()))
    188         style()->setPaddingBottom(Length(static_cast<int>(gRootBottomPadding * style()->fontSize()), Fixed));
    189 
    190 
    191     RenderBlock::layout();
    192 }
    193 
    194 }
    195 
    196 #endif // ENABLE(MATHML)
    197 
    198 
    199