diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp')
-rw-r--r-- | Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp | 492 |
1 files changed, 219 insertions, 273 deletions
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp index 14afbdfa5..0e975c730 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp @@ -30,334 +30,280 @@ #include "RenderMathMLRoot.h" -#include "FontCache.h" #include "GraphicsContext.h" #include "PaintInfo.h" #include "RenderIterator.h" -#include "RenderMathMLRadicalOperator.h" -#include "RenderMathMLSquareRoot.h" +#include "RenderMathMLRow.h" namespace WebCore { -// RenderMathMLRoot implements drawing of radicals via the <mroot> and <msqrt> elements. For valid MathML elements, the DOM is -// -// <mroot> Base Index </mroot> -// <msqrt> Child1 Child2 ... ChildN </msqrt> -// -// and the structure of the render tree will be -// -// IndexWrapper RadicalWrapper BaseWrapper -// -// where RadicalWrapper contains an <mo>√</mo>. -// For <mroot>, the IndexWrapper and BaseWrapper should contain exactly one child (Index and Base respectively). -// For <msqrt>, the IndexWrapper should be empty and the BaseWrapper can contain any number of children (Child1, ... ChildN). -// -// In order to accept invalid markup and to handle <mroot> and <msqrt> consistently, we will allow any number of children in the BaseWrapper of <mroot> too. -// We will allow the IndexWrapper to be empty and it will always contain the last child of the <mroot> if there are at least 2 elements. - -RenderMathMLRoot::RenderMathMLRoot(Element& element, Ref<RenderStyle>&& style) - : RenderMathMLBlock(element, WTFMove(style)) +// FIXME: This whole file should be changed to work with various writing modes. See https://bugs.webkit.org/show_bug.cgi?id=48951. + +// Threshold above which the radical shape is modified to look nice with big bases (em) +const float gThresholdBaseHeightEms = 1.5f; +// Normal width of the front of the radical sign, before the base & overbar (em) +const float gFrontWidthEms = 0.75f; +// Gap between the base and overbar (em) +const float gSpaceAboveEms = 0.2f; +// Horizontal position of the bottom point of the radical (* frontWidth) +const float gRadicalBottomPointXFront = 0.5f; +// Lower the radical sign's bottom point (px) +const int gRadicalBottomPointLower = 3; +// Horizontal position of the top left point of the radical "dip" (* frontWidth) +const float gRadicalDipLeftPointXFront = 0.8f; +// Vertical position of the top left point of a sqrt radical "dip" (* baseHeight) +const float gSqrtRadicalDipLeftPointYPos = 0.5f; +// Vertical position of the top left point of an nth root radical "dip" (* baseHeight) +const float gRootRadicalDipLeftPointYPos = 0.625f; +// Vertical shift of the left end point of the radical (em) +const float gRadicalLeftEndYShiftEms = 0.05f; +// Additional bottom root padding if baseHeight > threshold (em) +const float gBigRootBottomPaddingEms = 0.2f; + +// Radical line thickness (em) +const float gRadicalLineThicknessEms = 0.02f; +// Radical thick line thickness (em) +const float gRadicalThickLineThicknessEms = 0.1f; + +RenderMathMLRoot::RenderMathMLRoot(Element& element, PassRef<RenderStyle> style) + : RenderMathMLBlock(element, std::move(style)) + , m_intrinsicPaddingBefore(0) + , m_intrinsicPaddingAfter(0) + , m_intrinsicPaddingStart(0) + , m_intrinsicPaddingEnd(0) { } -RenderMathMLRoot::RenderMathMLRoot(Document& document, Ref<RenderStyle>&& style) - : RenderMathMLBlock(document, WTFMove(style)) +RenderMathMLRoot::RenderMathMLRoot(Document& document, PassRef<RenderStyle> style) + : RenderMathMLBlock(document, std::move(style)) + , m_intrinsicPaddingBefore(0) + , m_intrinsicPaddingAfter(0) + , m_intrinsicPaddingStart(0) + , m_intrinsicPaddingEnd(0) { } - -RenderMathMLRootWrapper* RenderMathMLRoot::baseWrapper() const +LayoutUnit RenderMathMLRoot::paddingTop() const { - ASSERT(!isEmpty()); - return downcast<RenderMathMLRootWrapper>(lastChild()); + LayoutUnit result = computedCSSPaddingTop(); + switch (style().writingMode()) { + case TopToBottomWritingMode: + return result + m_intrinsicPaddingBefore; + case BottomToTopWritingMode: + return result + m_intrinsicPaddingAfter; + case LeftToRightWritingMode: + case RightToLeftWritingMode: + return result + (style().isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd); + } + ASSERT_NOT_REACHED(); + return result; } -RenderMathMLBlock* RenderMathMLRoot::radicalWrapper() const +LayoutUnit RenderMathMLRoot::paddingBottom() const { - ASSERT(!isEmpty()); - return downcast<RenderMathMLBlock>(lastChild()->previousSibling()); + LayoutUnit result = computedCSSPaddingBottom(); + switch (style().writingMode()) { + case TopToBottomWritingMode: + return result + m_intrinsicPaddingAfter; + case BottomToTopWritingMode: + return result + m_intrinsicPaddingBefore; + case LeftToRightWritingMode: + case RightToLeftWritingMode: + return result + (style().isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart); + } + ASSERT_NOT_REACHED(); + return result; } -RenderMathMLRootWrapper* RenderMathMLRoot::indexWrapper() const +LayoutUnit RenderMathMLRoot::paddingLeft() const { - ASSERT(!isEmpty()); - return is<RenderMathMLSquareRoot>(*this) ? nullptr : downcast<RenderMathMLRootWrapper>(firstChild()); + LayoutUnit result = computedCSSPaddingLeft(); + switch (style().writingMode()) { + case LeftToRightWritingMode: + return result + m_intrinsicPaddingBefore; + case RightToLeftWritingMode: + return result + m_intrinsicPaddingAfter; + case TopToBottomWritingMode: + case BottomToTopWritingMode: + return result + (style().isLeftToRightDirection() ? m_intrinsicPaddingStart : m_intrinsicPaddingEnd); + } + ASSERT_NOT_REACHED(); + return result; } -RenderMathMLRadicalOperator* RenderMathMLRoot::radicalOperator() const +LayoutUnit RenderMathMLRoot::paddingRight() const { - ASSERT(!isEmpty()); - return downcast<RenderMathMLRadicalOperator>(radicalWrapper()->firstChild()); + LayoutUnit result = computedCSSPaddingRight(); + switch (style().writingMode()) { + case RightToLeftWritingMode: + return result + m_intrinsicPaddingBefore; + case LeftToRightWritingMode: + return result + m_intrinsicPaddingAfter; + case TopToBottomWritingMode: + case BottomToTopWritingMode: + return result + (style().isLeftToRightDirection() ? m_intrinsicPaddingEnd : m_intrinsicPaddingStart); + } + ASSERT_NOT_REACHED(); + return result; } -void RenderMathMLRoot::restructureWrappers() +LayoutUnit RenderMathMLRoot::paddingBefore() const { - ASSERT(!isEmpty()); - - auto base = baseWrapper(); - auto index = indexWrapper(); - auto radical = radicalWrapper(); - - // For visual consistency with the initial state, we remove the radical when the base/index wrappers become empty. - if (base->isEmpty() && (!index || index->isEmpty())) { - if (!radical->isEmpty()) { - auto child = radicalOperator(); - radical->removeChild(*child); - child->destroy(); - } - // FIXME: early return!!! - } - - if (radical->isEmpty()) { - // We create the radical operator. - RenderPtr<RenderMathMLRadicalOperator> radicalOperator = createRenderer<RenderMathMLRadicalOperator>(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), FLEX)); - radicalOperator->initializeStyle(); - radical->addChild(radicalOperator.leakPtr()); - } - - if (isRenderMathMLSquareRoot()) - return; - - if (auto childToMove = base->lastChild()) { - // We move the last child of the base wrapper into the index wrapper if the index wrapper is empty and the base wrapper has at least two children. - if (childToMove->previousSibling() && index->isEmpty()) { - base->removeChildWithoutRestructuring(*childToMove); - index->addChild(childToMove); - } - } - - if (auto childToMove = index->firstChild()) { - // We move the first child of the index wrapper into the base wrapper if: - // - either the index wrapper has at least two children. - // - or the base wrapper is empty but the index wrapper is not. - if (childToMove->nextSibling() || base->isEmpty()) { - index->removeChildWithoutRestructuring(*childToMove); - base->addChild(childToMove); - } - } + return computedCSSPaddingBefore() + m_intrinsicPaddingBefore; } -void RenderMathMLRoot::addChild(RenderObject* newChild, RenderObject* beforeChild) +LayoutUnit RenderMathMLRoot::paddingAfter() const { - if (isEmpty()) { - if (!isRenderMathMLSquareRoot()) { - // We add the IndexWrapper. - RenderMathMLBlock::addChild(RenderMathMLRootWrapper::createAnonymousWrapper(this).leakPtr()); - } - - // We create the radicalWrapper - RenderMathMLBlock::addChild(RenderMathMLBlock::createAnonymousMathMLBlock().leakPtr()); - - // We create the BaseWrapper. - RenderMathMLBlock::addChild(RenderMathMLRootWrapper::createAnonymousWrapper(this).leakPtr()); - - updateStyle(); - } - - // We insert the child. - auto base = baseWrapper(); - auto index = indexWrapper(); - RenderElement* actualParent; - RenderElement* actualBeforeChild; - if (is<RenderMathMLSquareRoot>(*this)) { - // For square root, we always insert the child into the base wrapper. - actualParent = base; - if (beforeChild && beforeChild->parent() == base) - actualBeforeChild = downcast<RenderElement>(beforeChild); - else - actualBeforeChild = nullptr; - } else { - // For mroot, we insert the child into the parent of beforeChild, or at the end of the index. The wrapper structure is reorganize below. - actualParent = beforeChild ? beforeChild->parent() : nullptr; - if (actualParent == base || actualParent == index) - actualBeforeChild = downcast<RenderElement>(beforeChild); - else { - actualParent = index; - actualBeforeChild = nullptr; - } - } - actualParent->addChild(newChild, actualBeforeChild); - restructureWrappers(); + return computedCSSPaddingAfter() + m_intrinsicPaddingAfter; } -void RenderMathMLRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) +LayoutUnit RenderMathMLRoot::paddingStart() const { - RenderMathMLBlock::styleDidChange(diff, oldStyle); - if (!isEmpty()) - updateStyle(); + return computedCSSPaddingStart() + m_intrinsicPaddingStart; } -void RenderMathMLRoot::updateFromElement() +LayoutUnit RenderMathMLRoot::paddingEnd() const { - RenderMathMLBlock::updateFromElement(); - if (!isEmpty()) - updateStyle(); + return computedCSSPaddingEnd() + m_intrinsicPaddingEnd; } -void RenderMathMLRoot::updateStyle() +void RenderMathMLRoot::addChild(RenderObject* newChild, RenderObject* beforeChild) { - ASSERT(!isEmpty()); - - // We set some constants to draw the radical, as defined in the OpenType MATH tables. - - m_ruleThickness = 0.05f * style().fontCascade().size(); - - // FIXME: The recommended default for m_verticalGap in displaystyle is rule thickness + 1/4 x-height (https://bugs.webkit.org/show_bug.cgi?id=118737). - m_verticalGap = 11 * m_ruleThickness / 4; - m_extraAscender = m_ruleThickness; - LayoutUnit kernBeforeDegree = 5 * style().fontCascade().size() / 18; - LayoutUnit kernAfterDegree = -10 * style().fontCascade().size() / 18; - m_degreeBottomRaisePercent = 0.6f; - - const auto& primaryFont = style().fontCascade().primaryFont(); - if (auto* mathData = style().fontCascade().primaryFont().mathData()) { - // FIXME: m_verticalGap should use RadicalDisplayStyleVertical in display mode (https://bugs.webkit.org/show_bug.cgi?id=118737). - m_verticalGap = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalVerticalGap); - m_ruleThickness = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalRuleThickness); - m_extraAscender = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalExtraAscender); - - if (!isRenderMathMLSquareRoot()) { - kernBeforeDegree = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalKernBeforeDegree); - kernAfterDegree = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalKernAfterDegree); - m_degreeBottomRaisePercent = mathData->getMathConstant(primaryFont, OpenTypeMathData::RadicalDegreeBottomRaisePercent); - } - } - - // We set the style of the anonymous wrappers. - - auto radical = radicalWrapper(); - auto radicalStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), FLEX); - radicalStyle.get().setMarginTop(Length(0, Fixed)); // This will be updated in RenderMathMLRoot::layout(). - radical->setStyle(WTFMove(radicalStyle)); - radical->setNeedsLayoutAndPrefWidthsRecalc(); - - auto base = baseWrapper(); - auto baseStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), FLEX); - baseStyle.get().setMarginTop(Length(0, Fixed)); // This will be updated in RenderMathMLRoot::layout(). - baseStyle.get().setAlignItemsPosition(ItemPositionBaseline); - base->setStyle(WTFMove(baseStyle)); - base->setNeedsLayoutAndPrefWidthsRecalc(); - - if (!isRenderMathMLSquareRoot()) { - // For mroot, we also set the style of the index wrapper. - auto index = indexWrapper(); - auto indexStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), FLEX); - indexStyle.get().setMarginTop(Length(0, Fixed)); // This will be updated in RenderMathMLRoot::layout(). - indexStyle.get().setMarginStart(Length(kernBeforeDegree, Fixed)); - indexStyle.get().setMarginEnd(Length(kernAfterDegree, Fixed)); - indexStyle.get().setAlignItemsPosition(ItemPositionBaseline); - index->setStyle(WTFMove(indexStyle)); - index->setNeedsLayoutAndPrefWidthsRecalc(); - } + // Insert an implicit <mrow> for <mroot> as well as <msqrt>, to ensure firstChild() will have a box + // to measure and store a glyph-based height for preferredLogicalHeightAfterSizing. + if (!firstChild()) + RenderMathMLBlock::addChild(RenderMathMLRow::createAnonymousWithParentRenderer(*this).leakPtr()); + + // An <mroot>'s index has { position: absolute }. + if (newChild->style().position() == AbsolutePosition) + RenderMathMLBlock::addChild(newChild); + else + toRenderElement(firstChild())->addChild(newChild, beforeChild && beforeChild->parent() == firstChild() ? beforeChild : 0); } -Optional<int> RenderMathMLRoot::firstLineBaseline() const +RenderBox* RenderMathMLRoot::index() const { - if (!isEmpty()) { - auto base = baseWrapper(); - return static_cast<int>(lroundf(base->firstLineBaseline().valueOr(-1) + base->marginTop())); - } - - return RenderMathMLBlock::firstLineBaseline(); + if (!firstChild()) + return 0; + RenderObject* index = firstChild()->nextSibling(); + if (!index || !index->isBox()) + return 0; + return toRenderBox(index); } void RenderMathMLRoot::layout() { - if (isEmpty()) { - RenderMathMLBlock::layout(); - return; - } - - // FIXME: It seems that changing the top margin of the base below modifies its logical height and leads to reftest failures. - // For now, we workaround that by avoiding to recompute the child margins if they were not reset in updateStyle(). - auto base = baseWrapper(); - if (base->marginTop() > 0) { - RenderMathMLBlock::layout(); - return; - } + for (auto& box : childrenOfType<RenderBox>(*this)) + box.layoutIfNeeded(); - // We layout the children. - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->needsLayout()) - downcast<RenderElement>(*child).layout(); + int baseHeight = firstChild() && firstChild()->isBox() ? roundToInt(toRenderBox(firstChild())->logicalHeight()) : style().fontSize(); + int frontWidth = lroundf(gFrontWidthEms * style().fontSize()); + + // Base height above which the shape of the root changes + float thresholdHeight = gThresholdBaseHeightEms * style().fontSize(); + if (baseHeight > thresholdHeight && thresholdHeight) { + float shift = std::min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); + m_overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); + m_intrinsicPaddingAfter = lroundf(gBigRootBottomPaddingEms * style().fontSize()); + } else { + m_overbarLeftPointShift = 0; + m_intrinsicPaddingAfter = 0; } + + int rootPad = lroundf(gSpaceAboveEms * style().fontSize()); + m_intrinsicPaddingBefore = rootPad; + m_indexTop = 0; + if (RenderBox* index = this->index()) { + m_intrinsicPaddingStart = roundToInt(index->maxPreferredLogicalWidth()) + m_overbarLeftPointShift; + + int indexHeight = roundToInt(index->logicalHeight()); + int partDipHeight = lroundf((1 - gRootRadicalDipLeftPointYPos) * baseHeight); + int rootExtraTop = partDipHeight + indexHeight - (baseHeight + rootPad); + if (rootExtraTop > 0) + m_intrinsicPaddingBefore += rootExtraTop; + else + m_indexTop = - rootExtraTop; + } else + m_intrinsicPaddingStart = frontWidth; - auto radical = radicalOperator(); - if (radical) { - // We stretch the radical sign to cover the height of the base wrapper. - float baseHeight = base->logicalHeight(); - float baseHeightAboveBaseline = base->firstLineBaseline().valueOr(baseHeight); - float baseDepthBelowBaseline = baseHeight - baseHeightAboveBaseline; - baseHeightAboveBaseline += m_verticalGap; - radical->stretchTo(baseHeightAboveBaseline, baseDepthBelowBaseline); - - // We modify the top margins to adjust the vertical positions of wrappers. - float radicalTopMargin = m_extraAscender; - float baseTopMargin = m_verticalGap + m_ruleThickness + m_extraAscender; - if (!isRenderMathMLSquareRoot()) { - // For mroot, we try to place the index so the space below its baseline is m_degreeBottomRaisePercent times the height of the radical. - auto index = indexWrapper(); - float indexHeight = 0; - if (!index->isEmpty()) - indexHeight = downcast<RenderBlock>(*index->firstChild()).logicalHeight(); - float indexTopMargin = (1.0 - m_degreeBottomRaisePercent) * radical->stretchSize() + radicalTopMargin - indexHeight; - if (indexTopMargin < 0) { - // If the index is too tall, we must add space at the top of renderer. - radicalTopMargin -= indexTopMargin; - baseTopMargin -= indexTopMargin; - indexTopMargin = 0; - } - index->style().setMarginTop(Length(indexTopMargin, Fixed)); - } - radical->style().setMarginTop(Length(radicalTopMargin, Fixed)); - base->style().setMarginTop(Length(baseTopMargin, Fixed)); - } + // FIXME: We should rewrite RenderMathMLRoot to rewrite -webkit-flex-order to get rid of the need + // for intrinsic padding. See https://bugs.webkit.org/show_bug.cgi?id=107151#c2. + // FIXME: We should make it so that the preferred width of RenderMathMLRoots doesn't change during layout. + // Technically, we currently only need to set the dirty bit here if one of the member variables above changes. + setPreferredLogicalWidthsDirty(true); RenderMathMLBlock::layout(); + + if (RenderBox* index = this->index()) + index->setLogicalTop(m_indexTop); } void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); - if (isEmpty() || info.context().paintingDisabled() || style().visibility() != VISIBLE) + if (info.context->paintingDisabled() || style().visibility() != VISIBLE) return; - - auto base = baseWrapper(); - auto radical = radicalOperator(); - if (!base || !radical || !m_ruleThickness) - return; - - // We draw the radical line. - GraphicsContextStateSaver stateSaver(info.context()); - - info.context().setStrokeThickness(m_ruleThickness); - info.context().setStrokeStyle(SolidStroke); - info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor)); - - // The preferred width of the radical is sometimes incorrect, so we draw a slightly longer line to ensure it touches the radical symbol (https://bugs.webkit.org/show_bug.cgi?id=130326). - LayoutUnit sizeError = radical->trailingSpaceError(); - IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + base->location() + LayoutPoint(-sizeError, -(m_verticalGap + m_ruleThickness / 2))); - info.context().drawLine(adjustedPaintOffset, roundedIntPoint(LayoutPoint(adjustedPaintOffset.x() + base->offsetWidth() + sizeError, adjustedPaintOffset.y()))); -} - -RenderPtr<RenderMathMLRootWrapper> RenderMathMLRootWrapper::createAnonymousWrapper(RenderMathMLRoot* renderObject) -{ - RenderPtr<RenderMathMLRootWrapper> newBlock = createRenderer<RenderMathMLRootWrapper>(renderObject->document(), RenderStyle::createAnonymousStyleWithDisplay(&renderObject->style(), FLEX)); - newBlock->initializeStyle(); - return newBlock; -} - -void RenderMathMLRootWrapper::removeChildWithoutRestructuring(RenderObject& child) -{ - RenderMathMLBlock::removeChild(child); -} - -void RenderMathMLRootWrapper::removeChild(RenderObject& child) -{ - RenderMathMLBlock::removeChild(child); - - if (!(beingDestroyed() || documentBeingDestroyed())) - downcast<RenderMathMLRoot>(*parent()).restructureWrappers(); + + IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + contentBoxRect().location()); + + int startX = adjustedPaintOffset.x(); + int frontWidth = lroundf(gFrontWidthEms * style().fontSize()); + int overbarWidth = roundToInt(contentLogicalWidth()) + m_overbarLeftPointShift; + + int baseHeight = roundToInt(contentLogicalHeight()); + int rootPad = lroundf(gSpaceAboveEms * style().fontSize()); + adjustedPaintOffset.setY(adjustedPaintOffset.y() - rootPad); + + float radicalDipLeftPointYPos = (index() ? gRootRadicalDipLeftPointYPos : gSqrtRadicalDipLeftPointYPos) * baseHeight; + + FloatPoint overbarLeftPoint(startX - m_overbarLeftPointShift, adjustedPaintOffset.y()); + FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); + FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + radicalDipLeftPointYPos); + FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style().fontSize()); + + GraphicsContextStateSaver stateSaver(*info.context); + + info.context->setStrokeThickness(gRadicalLineThicknessEms * style().fontSize()); + info.context->setStrokeStyle(SolidStroke); + info.context->setStrokeColor(style().visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); + info.context->setLineJoin(MiterJoin); + info.context->setMiterLimit(style().fontSize()); + + Path root; + + root.moveTo(FloatPoint(overbarLeftPoint.x() + overbarWidth, adjustedPaintOffset.y())); + // draw top + root.addLineTo(overbarLeftPoint); + // draw from top left corner to bottom point of radical + root.addLineTo(bottomPoint); + // draw from bottom point to top of left part of radical base "dip" + root.addLineTo(dipLeftPoint); + // draw to end + root.addLineTo(leftEnd); + + info.context->strokePath(root); + + GraphicsContextStateSaver maskStateSaver(*info.context); + + // Build a mask to draw the thick part of the root. + Path mask; + + mask.moveTo(overbarLeftPoint); + mask.addLineTo(bottomPoint); + mask.addLineTo(dipLeftPoint); + mask.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y())); + + info.context->clip(mask); + + // Draw the thick part of the root. + info.context->setStrokeThickness(gRadicalThickLineThicknessEms * style().fontSize()); + info.context->setLineCap(SquareCap); + + Path line; + line.moveTo(bottomPoint); + line.addLineTo(dipLeftPoint); + + info.context->strokePath(line); } } |