1/* 2 * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved. 3 * Copyright (C) 2010 François Sausset (sausset@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 37namespace WebCore { 38 39using namespace MathMLNames; 40 41static const float gLineThin = 0.33f; 42static const float gLineMedium = 1.f; 43static const float gLineThick = 3.f; 44static const float gFractionBarWidth = 0.05f; 45 46RenderMathMLFraction::RenderMathMLFraction(Element* element) 47 : RenderMathMLBlock(element) 48 , m_lineThickness(gLineMedium) 49{ 50} 51 52void RenderMathMLFraction::fixChildStyle(RenderObject* child) 53{ 54 ASSERT(child->isAnonymous() && child->style()->refCount() == 1); 55 child->style()->setFlexDirection(FlowColumn); 56} 57 58// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. Move parts 59// of this to fixChildStyle or other methods, and call them when needed. 60void RenderMathMLFraction::updateFromElement() 61{ 62 // FIXME: mfrac where bevelled=true will need to reorganize the descendants 63 if (isEmpty()) 64 return; 65 66 Element* fraction = toElement(node()); 67 68 RenderObject* numeratorWrapper = firstChild(); 69 RenderObject* denominatorWrapper = numeratorWrapper->nextSibling(); 70 if (!denominatorWrapper) 71 return; 72 73 String thickness = fraction->getAttribute(MathMLNames::linethicknessAttr); 74 m_lineThickness = gLineMedium; 75 if (equalIgnoringCase(thickness, "thin")) 76 m_lineThickness = gLineThin; 77 else if (equalIgnoringCase(thickness, "medium")) 78 m_lineThickness = gLineMedium; 79 else if (equalIgnoringCase(thickness, "thick")) 80 m_lineThickness = gLineThick; 81 else { 82 bool converted = false; 83 int thicknessIntValue = thickness.toIntStrict(&converted); 84 if (converted) 85 m_lineThickness = thicknessIntValue; 86 } 87 88 // Update the style for the padding of the denominator for the line thickness 89 lastChild()->style()->setPaddingTop(Length(static_cast<int>(m_lineThickness), Fixed)); 90} 91 92void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* /* beforeChild */) 93{ 94 if (isEmpty()) { 95 RenderMathMLBlock* numeratorWrapper = createAnonymousMathMLBlock(); 96 RenderMathMLBlock::addChild(numeratorWrapper); 97 fixChildStyle(numeratorWrapper); 98 99 RenderMathMLBlock* denominatorWrapper = createAnonymousMathMLBlock(); 100 RenderMathMLBlock::addChild(denominatorWrapper); 101 fixChildStyle(denominatorWrapper); 102 } 103 104 if (firstChild()->isEmpty()) 105 firstChild()->addChild(child); 106 else 107 lastChild()->addChild(child); 108 109 updateFromElement(); 110} 111 112void RenderMathMLFraction::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 113{ 114 RenderMathMLBlock::styleDidChange(diff, oldStyle); 115 116 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) 117 fixChildStyle(child); 118 updateFromElement(); 119} 120 121RenderMathMLOperator* RenderMathMLFraction::unembellishedOperator() 122{ 123 RenderObject* numeratorWrapper = firstChild(); 124 if (!numeratorWrapper) 125 return 0; 126 RenderObject* numerator = numeratorWrapper->firstChild(); 127 if (!numerator || !numerator->isRenderMathMLBlock()) 128 return 0; 129 return toRenderMathMLBlock(numerator)->unembellishedOperator(); 130} 131 132void RenderMathMLFraction::layout() 133{ 134 updateFromElement(); 135 136 // Adjust the fraction line thickness for the zoom 137 if (lastChild() && lastChild()->isRenderBlock()) 138 m_lineThickness *= ceilf(gFractionBarWidth * style()->fontSize()); 139 140 RenderMathMLBlock::layout(); 141} 142 143void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset) 144{ 145 RenderMathMLBlock::paint(info, paintOffset); 146 if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground) 147 return; 148 149 RenderBox* denominatorWrapper = lastChildBox(); 150 if (!denominatorWrapper || !m_lineThickness) 151 return; 152 153 IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + denominatorWrapper->location() + LayoutPoint(0, m_lineThickness / 2)); 154 155 GraphicsContextStateSaver stateSaver(*info.context); 156 157 info.context->setStrokeThickness(m_lineThickness); 158 info.context->setStrokeStyle(SolidStroke); 159 info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB); 160 161 info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + denominatorWrapper->pixelSnappedOffsetWidth(), adjustedPaintOffset.y())); 162} 163 164int RenderMathMLFraction::firstLineBoxBaseline() const 165{ 166 if (RenderBox* denominatorWrapper = lastChildBox()) 167 return denominatorWrapper->logicalTop() + static_cast<int>(lroundf((m_lineThickness + style()->fontMetrics().xHeight()) / 2)); 168 return RenderMathMLBlock::firstLineBoxBaseline(); 169} 170 171} 172 173#endif // ENABLE(MATHML) 174