1/* 2 * Copyright (C) 2014 Gurpreet Kaur (k.gurpreet@samsung.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#define _USE_MATH_DEFINES 1 27#include "config.h" 28 29#if ENABLE(MATHML) 30#include "RenderMathMLMenclose.h" 31 32#include "GraphicsContext.h" 33#include "MathMLMencloseElement.h" 34#include "PaintInfo.h" 35#include "RenderMathMLSquareRoot.h" 36#include <wtf/MathExtras.h> 37 38namespace WebCore { 39 40using namespace MathMLNames; 41 42RenderMathMLMenclose::RenderMathMLMenclose(Element& element, PassRef<RenderStyle> style) 43 : RenderMathMLRow(element, WTF::move(style)) 44{ 45} 46 47void RenderMathMLMenclose::addChild(RenderObject* newChild, RenderObject* beforeChild) 48{ 49 MathMLMencloseElement* menclose = toMathMLMencloseElement(element()); 50 // Allow an anonymous RenderMathMLSquareRoot to handle drawing the radical 51 // notation, rather than duplicating the code needed to paint a root. 52 if (!firstChild() && menclose->isRadical()) 53 RenderMathMLBlock::addChild(RenderMathMLSquareRoot::createAnonymousWithParentRenderer(*this).leakPtr()); 54 55 if (newChild) { 56 if (firstChild() && menclose->isRadical()) 57 toRenderElement(firstChild())->addChild(newChild, beforeChild && beforeChild->parent() == firstChild() ? beforeChild : nullptr); 58 else 59 RenderMathMLBlock::addChild(newChild, beforeChild); 60 } 61} 62 63void RenderMathMLMenclose::computePreferredLogicalWidths() 64{ 65 ASSERT(preferredLogicalWidthsDirty()); 66 67 RenderMathMLBlock::computePreferredLogicalWidths(); 68 const int paddingTop = 6; 69 70 MathMLMencloseElement* menclose = toMathMLMencloseElement(element()); 71 const Vector<String>& notationValues = menclose->notationValues(); 72 size_t notationalValueSize = notationValues.size(); 73 for (size_t i = 0; i < notationalValueSize; i++) { 74 if (notationValues[i] == "circle") { 75 m_minPreferredLogicalWidth = minPreferredLogicalWidth() * float(M_SQRT2); 76 m_maxPreferredLogicalWidth = maxPreferredLogicalWidth() * float(M_SQRT2); 77 } 78 } 79 80 if (menclose->isDefaultLongDiv()) { 81 style().setPaddingTop(Length(paddingTop, Fixed)); 82 style().setPaddingLeft(Length(menclose->longDivLeftPadding().toInt(), Fixed)); 83 } 84 setPreferredLogicalWidthsDirty(false); 85} 86 87void RenderMathMLMenclose::updateLogicalHeight() 88{ 89 MathMLMencloseElement* menclose = toMathMLMencloseElement(element()); 90 const Vector<String>& notationValues = menclose->notationValues(); 91 size_t notationalValueSize = notationValues.size(); 92 for (size_t i = 0; i < notationalValueSize; i++) 93 if (notationValues[i] == "circle") 94 setLogicalHeight(logicalHeight() * float(M_SQRT2)); 95} 96 97void RenderMathMLMenclose::paint(PaintInfo& info, const LayoutPoint& paintOffset) 98{ 99 RenderMathMLBlock::paint(info, paintOffset); 100 101 if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE) 102 return; 103 104 MathMLMencloseElement* menclose = toMathMLMencloseElement(element()); 105 const Vector<String>& notationValues = menclose->notationValues(); 106 size_t notationalValueSize = notationValues.size(); 107 bool isDefaultLongDiv = menclose->isDefaultLongDiv(); 108 if ((notationalValueSize && checkNotationalValuesValidity(notationValues)) || isDefaultLongDiv) { 109 IntRect rect = absoluteBoundingBoxRect(); 110 int left = rect.x(); 111 int top = rect.y(); 112 int boxWidth = rect.width(); 113 int boxHeight = rect.height(); 114 int halfboxWidth = rect.width() / 2; 115 int halfboxHeight = rect.height() / 2; 116 117 GraphicsContextStateSaver stateSaver(*info.context); 118 info.context->setStrokeThickness(1); 119 info.context->setStrokeStyle(SolidStroke); 120 info.context->setStrokeColor(style().visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); 121 // TODO add support for notation value updiagonalarrow https://bugs.webkit.org/show_bug.cgi?id=127466 122 for (size_t i = 0; i < notationalValueSize; i++) { 123 if (notationValues[i] == "updiagonalstrike") 124 info.context->drawLine(IntPoint(left, top + boxHeight), IntPoint(left + boxWidth, top)); 125 else if (notationValues[i] == "downdiagonalstrike") 126 info.context->drawLine(IntPoint(left, top), IntPoint(left + boxWidth, top + boxHeight)); 127 else if (notationValues[i] == "verticalstrike") 128 info.context->drawLine(IntPoint(left + halfboxWidth, top), IntPoint(left + halfboxWidth, top + boxHeight)); 129 else if (notationValues[i] == "horizontalstrike") 130 info.context->drawLine(IntPoint(left, top + halfboxHeight), IntPoint(left + boxWidth, top + halfboxHeight)); 131 else if (notationValues[i] == "circle") { 132 info.context->setFillColor(Color::transparent, ColorSpaceDeviceRGB); 133 info.context->drawEllipse(rect); 134 } else if (notationValues[i] == "longdiv") 135 isDefaultLongDiv = true; 136 } 137 if (isDefaultLongDiv) { 138 Path root; 139 int midxPoint = 0; 140 root.moveTo(FloatPoint(left, top)); 141 int childLeft = firstChild() ? firstChild()->absoluteBoundingBoxRect().x() : 0; 142 if (childLeft) 143 midxPoint= childLeft - left; 144 else 145 midxPoint = style().paddingLeft().value(); 146 root.addBezierCurveTo(FloatPoint(left, top), FloatPoint(left + midxPoint, top + halfboxHeight), FloatPoint(left, top + boxHeight)); 147 info.context->strokePath(root); 148 if (isDefaultLongDiv) 149 info.context->drawLine(IntPoint(left, top), IntPoint(left + boxWidth + midxPoint, top)); 150 } 151 } 152} 153 154bool RenderMathMLMenclose::checkNotationalValuesValidity(const Vector<String>& attr) const 155{ 156 size_t attrSize = attr.size(); 157 for (size_t i = 0; i < attrSize; i++) { 158 if (attr[i] == "updiagonalstrike" || attr[i] == "downdiagonalstrike" || attr[i] == "horizontalstrike" || attr[i] == "verticalstrike" 159 || attr[i] == "circle" || attr[i] == "longdiv") 160 return true; 161 } 162 return false; 163} 164 165} 166#endif // ENABLE(MATHML) 167