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 "RenderMathMLFraction.h" 32 33 #include "GraphicsContext.h" 34 #include "MathMLNames.h" 35 #include "PaintInfo.h" 36 #include "RenderText.h" 37 38 namespace WebCore { 39 40 using namespace MathMLNames; 41 42 static const float gHorizontalPad = 0.2f; 43 static const float gLineThin = 0.33f; 44 static const float gLineMedium = 1.f; 45 static const float gLineThick = 3.f; 46 static const float gFractionBarWidth = 0.05f; 47 static const float gDenominatorPad = 0.1f; 48 49 RenderMathMLFraction::RenderMathMLFraction(Element* fraction) 50 : RenderMathMLBlock(fraction) 51 , m_lineThickness(gLineMedium) 52 { 53 setChildrenInline(false); 54 } 55 56 void RenderMathMLFraction::updateFromElement() 57 { 58 // FIXME: mfrac where bevelled=true will need to reorganize the descendants 59 if (isEmpty()) 60 return; 61 62 Element* fraction = static_cast<Element*>(node()); 63 64 RenderObject* numerator = firstChild(); 65 String nalign = fraction->getAttribute(MathMLNames::numalignAttr); 66 if (equalIgnoringCase(nalign, "left")) 67 numerator->style()->setTextAlign(LEFT); 68 else if (equalIgnoringCase(nalign, "right")) 69 numerator->style()->setTextAlign(RIGHT); 70 else 71 numerator->style()->setTextAlign(CENTER); 72 73 RenderObject* denominator = numerator->nextSibling(); 74 if (!denominator) 75 return; 76 77 String dalign = fraction->getAttribute(MathMLNames::denomalignAttr); 78 if (equalIgnoringCase(dalign, "left")) 79 denominator->style()->setTextAlign(LEFT); 80 else if (equalIgnoringCase(dalign, "right")) 81 denominator->style()->setTextAlign(RIGHT); 82 else 83 denominator->style()->setTextAlign(CENTER); 84 85 // FIXME: parse units 86 String thickness = fraction->getAttribute(MathMLNames::linethicknessAttr); 87 m_lineThickness = gLineMedium; 88 if (equalIgnoringCase(thickness, "thin")) 89 m_lineThickness = gLineThin; 90 else if (equalIgnoringCase(thickness, "medium")) 91 m_lineThickness = gLineMedium; 92 else if (equalIgnoringCase(thickness, "thick")) 93 m_lineThickness = gLineThick; 94 else if (equalIgnoringCase(thickness, "0")) 95 m_lineThickness = 0; 96 97 // Update the style for the padding of the denominator for the line thickness 98 lastChild()->style()->setPaddingTop(Length(static_cast<int>(m_lineThickness + style()->fontSize() * gDenominatorPad), Fixed)); 99 } 100 101 void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* beforeChild) 102 { 103 RenderBlock* row = new (renderArena()) RenderMathMLBlock(node()); 104 RefPtr<RenderStyle> rowStyle = makeBlockStyle(); 105 106 rowStyle->setTextAlign(CENTER); 107 Length pad(static_cast<int>(rowStyle->fontSize() * gHorizontalPad), Fixed); 108 rowStyle->setPaddingLeft(pad); 109 rowStyle->setPaddingRight(pad); 110 111 // Only add padding for rows as denominators 112 bool isNumerator = isEmpty(); 113 if (!isNumerator) 114 rowStyle->setPaddingTop(Length(2, Fixed)); 115 116 row->setStyle(rowStyle.release()); 117 RenderBlock::addChild(row, beforeChild); 118 row->addChild(child); 119 updateFromElement(); 120 } 121 122 void RenderMathMLFraction::layout() 123 { 124 updateFromElement(); 125 126 // Adjust the fraction line thickness for the zoom 127 if (lastChild() && lastChild()->isRenderBlock()) 128 m_lineThickness *= ceilf(gFractionBarWidth * style()->fontSize()); 129 130 RenderBlock::layout(); 131 132 } 133 134 void RenderMathMLFraction::paint(PaintInfo& info, int tx, int ty) 135 { 136 RenderMathMLBlock::paint(info, tx, ty); 137 if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground) 138 return; 139 140 if (!firstChild() ||!m_lineThickness) 141 return; 142 143 int verticalOffset = 0; 144 // The children are always RenderMathMLBlock instances 145 if (firstChild()->isRenderMathMLBlock()) { 146 int adjustForThickness = m_lineThickness > 1 ? int(m_lineThickness / 2) : 1; 147 if (int(m_lineThickness) % 2 == 1) 148 adjustForThickness++; 149 RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild()); 150 if (numerator->isRenderMathMLRow()) 151 verticalOffset = numerator->offsetHeight() + adjustForThickness; 152 else 153 verticalOffset = numerator->offsetHeight(); 154 } 155 156 tx += x(); 157 ty += y() + verticalOffset; 158 159 info.context->save(); 160 161 info.context->setStrokeThickness(m_lineThickness); 162 info.context->setStrokeStyle(SolidStroke); 163 info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB); 164 165 info.context->drawLine(IntPoint(tx, ty), IntPoint(tx + offsetWidth(), ty)); 166 167 info.context->restore(); 168 } 169 170 int RenderMathMLFraction::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const 171 { 172 if (firstChild() && firstChild()->isRenderMathMLBlock()) { 173 RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild()); 174 RenderStyle* refStyle = style(); 175 if (previousSibling()) 176 refStyle = previousSibling()->style(); 177 else if (nextSibling()) 178 refStyle = nextSibling()->style(); 179 int shift = int(ceil((refStyle->fontMetrics().xHeight() + 1) / 2)); 180 return numerator->offsetHeight() + shift; 181 } 182 return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, lineDirection, linePositionMode); 183 } 184 185 } 186 187 188 #endif // ENABLE(MATHML) 189