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(MathMLInlineContainerElement& element, PassRef<RenderStyle> style) 47 : RenderMathMLBlock(element, WTF::move(style)) 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 RenderObject* numeratorWrapper = firstChild(); 67 RenderObject* denominatorWrapper = numeratorWrapper->nextSibling(); 68 if (!denominatorWrapper) 69 return; 70 71 String thickness = element().getAttribute(MathMLNames::linethicknessAttr); 72 m_lineThickness = gLineMedium; 73 if (equalIgnoringCase(thickness, "thin")) 74 m_lineThickness = gLineThin; 75 else if (equalIgnoringCase(thickness, "medium")) 76 m_lineThickness = gLineMedium; 77 else if (equalIgnoringCase(thickness, "thick")) 78 m_lineThickness = gLineThick; 79 else { 80 // This function parses the thickness attribute using gLineMedium as 81 // the default value. If the parsing fails, m_lineThickness will not be 82 // modified i.e. the default value will be used. 83 parseMathMLLength(thickness, m_lineThickness, &style(), false); 84 } 85 86 // Update the style for the padding of the denominator for the line thickness 87 lastChild()->style().setPaddingTop(Length(static_cast<int>(m_lineThickness), Fixed)); 88} 89 90void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* /* beforeChild */) 91{ 92 if (isEmpty()) { 93 RenderPtr<RenderMathMLBlock> numeratorWrapper = createAnonymousMathMLBlock(); 94 fixChildStyle(numeratorWrapper.get()); 95 RenderMathMLBlock::addChild(numeratorWrapper.leakPtr()); 96 97 RenderPtr<RenderMathMLBlock> denominatorWrapper = createAnonymousMathMLBlock(); 98 fixChildStyle(denominatorWrapper.get()); 99 RenderMathMLBlock::addChild(denominatorWrapper.leakPtr()); 100 } 101 102 if (firstChild()->isEmpty()) 103 toRenderElement(firstChild())->addChild(child); 104 else 105 toRenderElement(lastChild())->addChild(child); 106 107 updateFromElement(); 108} 109 110void RenderMathMLFraction::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 111{ 112 RenderMathMLBlock::styleDidChange(diff, oldStyle); 113 114 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) 115 fixChildStyle(child); 116 updateFromElement(); 117} 118 119RenderMathMLOperator* RenderMathMLFraction::unembellishedOperator() 120{ 121 RenderObject* numeratorWrapper = firstChild(); 122 if (!numeratorWrapper) 123 return 0; 124 RenderObject* numerator = numeratorWrapper->firstChildSlow(); 125 if (!numerator || !numerator->isRenderMathMLBlock()) 126 return 0; 127 return toRenderMathMLBlock(numerator)->unembellishedOperator(); 128} 129 130void RenderMathMLFraction::layout() 131{ 132 updateFromElement(); 133 134 // Adjust the fraction line thickness for the zoom 135 if (lastChild() && lastChild()->isRenderBlock()) 136 m_lineThickness *= ceilf(gFractionBarWidth * style().fontSize()); 137 138 RenderMathMLBlock::layout(); 139} 140 141void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset) 142{ 143 RenderMathMLBlock::paint(info, paintOffset); 144 if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE) 145 return; 146 147 RenderBox* denominatorWrapper = lastChildBox(); 148 if (!denominatorWrapper || !m_lineThickness) 149 return; 150 151 IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + denominatorWrapper->location() + LayoutPoint(0, m_lineThickness / 2)); 152 153 GraphicsContextStateSaver stateSaver(*info.context); 154 155 info.context->setStrokeThickness(m_lineThickness); 156 info.context->setStrokeStyle(SolidStroke); 157 info.context->setStrokeColor(style().visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB); 158 159 info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + denominatorWrapper->pixelSnappedOffsetWidth(), adjustedPaintOffset.y())); 160} 161 162int RenderMathMLFraction::firstLineBaseline() const 163{ 164 if (RenderBox* denominatorWrapper = lastChildBox()) 165 return denominatorWrapper->logicalTop() + static_cast<int>(lroundf((m_lineThickness + style().fontMetrics().xHeight()) / 2)); 166 return RenderMathMLBlock::firstLineBaseline(); 167} 168 169} 170 171#endif // ENABLE(MATHML) 172