diff options
author | Steve Block <steveblock@google.com> | 2011-05-18 13:36:51 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-24 15:38:28 +0100 |
commit | 2fc2651226baac27029e38c9d6ef883fa32084db (patch) | |
tree | e396d4bf89dcce6ed02071be66212495b1df1dec /Source/WebCore/rendering/svg | |
parent | b3725cedeb43722b3b175aaeff70552e562d2c94 (diff) | |
download | external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.zip external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.gz external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.bz2 |
Merge WebKit at r78450: Initial merge by git.
Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1
Diffstat (limited to 'Source/WebCore/rendering/svg')
19 files changed, 279 insertions, 101 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp index 0f5a55e..81a5cea 100644 --- a/Source/WebCore/rendering/svg/RenderSVGImage.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp @@ -122,7 +122,7 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) PaintInfo savedInfo(childPaintInfo); if (SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo)) { - Image* image = m_imageResource->image(); + RefPtr<Image> image = m_imageResource->image(); FloatRect destRect = m_objectBoundingBox; FloatRect srcRect(0, 0, image->width(), image->height()); @@ -130,7 +130,7 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, int, int) if (imageElement->preserveAspectRatio().align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) imageElement->preserveAspectRatio().transformRect(destRect, srcRect); - childPaintInfo.context->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect); + childPaintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect); } SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, savedInfo.context); diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index 91ffb5c..a8aa0c8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -26,11 +26,14 @@ #if ENABLE(SVG) #include "RenderSVGInlineText.h" +#include "CSSStyleSelector.h" #include "FloatConversion.h" #include "FloatQuad.h" #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" +#include "Settings.h" +#include "SVGImageBufferTools.h" #include "SVGInlineTextBox.h" #include "SVGRootInlineBox.h" #include "VisiblePosition.h" @@ -63,6 +66,7 @@ static PassRefPtr<StringImpl> applySVGWhitespaceRules(PassRefPtr<StringImpl> str RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> string) : RenderText(n, applySVGWhitespaceRules(string, false)) + , m_scalingFactor(1) { } @@ -74,6 +78,8 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle // The text metrics may be influenced by style changes. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) textRenderer->setNeedsPositioningValuesUpdate(); + + updateScaledFont(); } const RenderStyle* newStyle = style(); @@ -103,12 +109,12 @@ IntRect RenderSVGInlineText::localCaretRect(InlineBox* box, int caretOffset, int // Use the edge of the selection rect to determine the caret rect. if (static_cast<unsigned>(caretOffset) < textBox->start() + textBox->len()) { IntRect rect = textBox->selectionRect(0, 0, caretOffset, caretOffset + 1); - int x = box->isLeftToRightDirection() ? rect.x() : rect.right(); + int x = box->isLeftToRightDirection() ? rect.x() : rect.maxX(); return IntRect(x, rect.y(), caretWidth, rect.height()); } IntRect rect = textBox->selectionRect(0, 0, caretOffset - 1, caretOffset); - int x = box->isLeftToRightDirection() ? rect.right() : rect.x(); + int x = box->isLeftToRightDirection() ? rect.maxX() : rect.x(); return IntRect(x, rect.y(), caretWidth, rect.height()); } @@ -159,9 +165,7 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); - RenderStyle* style = this->style(); - ASSERT(style); - int baseline = style->font().ascent(); + float baseline = m_scaledFont.fontMetrics().floatAscent(); RenderBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); @@ -206,6 +210,39 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point) return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); } +void RenderSVGInlineText::updateScaledFont() +{ + computeNewScaledFontForStyle(this, style(), m_scalingFactor, m_scaledFont); +} + +void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, const RenderStyle* style, float& scalingFactor, Font& scaledFont) +{ + ASSERT(style); + ASSERT(renderer); + + Document* document = renderer->document(); + ASSERT(document); + + CSSStyleSelector* styleSelector = document->styleSelector(); + ASSERT(styleSelector); + + // Alter font-size to the right on-screen value, to avoid scaling the glyphs themselves. + AffineTransform ctm; + SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(renderer, ctm); + scalingFactor = narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); + if (scalingFactor == 1 || !scalingFactor) { + scalingFactor = 1; + scaledFont = style->font(); + return; + } + + FontDescription fontDescription(style->fontDescription()); + fontDescription.setComputedSize(fontDescription.computedSize() * scalingFactor); + + scaledFont = Font(fontDescription, 0, 0); + scaledFont.update(styleSelector->fontSelector()); +} + } #endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index f5247f6..9eed8cd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -40,6 +40,11 @@ public: const SVGTextLayoutAttributes& layoutAttributes() const { return m_attributes; } void storeLayoutAttributes(const SVGTextLayoutAttributes& attributes) { m_attributes = attributes; } + float scalingFactor() const { return m_scalingFactor; } + const Font& scaledFont() const { return m_scaledFont; } + void updateScaledFont(); + static void computeNewScaledFontForStyle(RenderObject*, const RenderStyle*, float& scalingFactor, Font& scaledFont); + private: virtual const char* renderName() const { return "RenderSVGInlineText"; } @@ -57,6 +62,8 @@ private: virtual IntRect linesBoundingBox() const; virtual InlineTextBox* createTextBox(); + float m_scalingFactor; + Font m_scaledFont; SVGTextLayoutAttributes m_attributes; }; diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp index 4ba4e0a..96514af 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -111,7 +111,7 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(Filter* fi builder->clearEffects(); return 0; } - builder->appendEffectToEffectReferences(effect); + builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(primitiveBoundingBoxMode, effect.get()); builder->add(effectElement->result(), effect); } @@ -208,13 +208,13 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, if (!lastEffect) return false; - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); FloatRect subRegion = lastEffect->maxEffectRect(); // At least one FilterEffect has a too big image size, // recalculate the effect sizes with new scale factors. if (!fitsInMaximumImageSize(subRegion.size(), scale)) { filterData->filter->setFilterResolution(scale); - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); } // If the drawingRegion is empty, we have something like <g filter=".."/>. @@ -290,16 +290,19 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo // This is the real filtering of the object. It just needs to be called on the // initial filtering process. We just take the stored filter result on a // second drawing. - if (!filterData->builded) { + if (!filterData->builded) filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release()); + + // Always true if filterData is just built (filterData->builded is false). + if (!lastEffect->hasResult()) { lastEffect->apply(); #if !PLATFORM(CG) ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB); #endif - filterData->builded = true; } + filterData->builded = true; ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { @@ -324,5 +327,31 @@ FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) return FloatRect(); } +void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute) +{ + HashMap<RenderObject*, FilterData*>::iterator it = m_filter.begin(); + HashMap<RenderObject*, FilterData*>::iterator end = m_filter.end(); + SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node()); + + for (; it != end; ++it) { + FilterData* filterData = it->second; + if (!filterData->builded) + continue; + + SVGFilterBuilder* builder = filterData->builder.get(); + FilterEffect* effect = builder->effectByRenderer(object); + if (!effect) + continue; + // Since all effects shares the same attribute value, all + // or none of them will be changed. + if (!primitve->setFilterEffectAttribute(effect, attribute)) + return; + builder->clearResultsRecursive(effect); + + // Repaint the image on the screen. + markClientForInvalidation(it->first, RepaintInvalidation); + } +} + } #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h index f9a15ce..c809f23 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h @@ -64,6 +64,7 @@ public: virtual ~RenderSVGResourceFilter(); virtual const char* renderName() const { return "RenderSVGResourceFilter"; } + virtual bool isSVGResourceFilter() const { return true; } virtual void removeAllClientsFromCache(bool markForInvalidation = true); virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); @@ -78,6 +79,8 @@ public: SVGUnitTypes::SVGUnitType filterUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->filterUnits()); } SVGUnitTypes::SVGUnitType primitiveUnits() const { return toUnitType(static_cast<SVGFilterElement*>(node())->primitiveUnits()); } + void primitiveAttributeChanged(RenderObject*, const QualifiedName&); + virtual RenderSVGResourceType resourceType() const { return s_resourceType; } static RenderSVGResourceType s_resourceType; diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index fc7362e..64df700 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -29,25 +29,29 @@ #if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGResourceFilterPrimitive.h" +#include "RenderSVGResource.h" #include "SVGFEImage.h" +#include "SVGFilter.h" namespace WebCore { -FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect, SVGFilter* filter) +FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) { FloatRect uniteRect; FloatRect subregionBoundingBox = effect->effectBoundaries(); FloatRect subregion = subregionBoundingBox; + SVGFilter* filter = static_cast<SVGFilter*>(effect->filter()); + ASSERT(filter); if (effect->filterEffectType() != FilterEffectTypeTile) { // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. if (unsigned numberOfInputEffects = effect->inputEffects().size()) { for (unsigned i = 0; i < numberOfInputEffects; ++i) - uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i), filter)); + uniteRect.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i))); } else uniteRect = filter->filterRegionInUserSpace(); } else { - determineFilterPrimitiveSubregion(effect->inputEffect(0), filter); + determineFilterPrimitiveSubregion(effect->inputEffect(0)); uniteRect = filter->filterRegionInUserSpace(); } @@ -90,7 +94,7 @@ FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(Fi // FEImage needs the unclipped subregion in absolute coordinates to determine the correct // destination rect in combination with preserveAspectRatio. if (effect->filterEffectType() == FilterEffectTypeImage) - reinterpret_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); + static_cast<FEImage*>(effect)->setAbsoluteSubregion(absoluteSubregion); // Clip every filter effect to the filter region. FloatRect absoluteScaledFilterRegion = filter->filterRegion(); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h index f25f62e..8176d29 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -30,25 +30,32 @@ #if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGHiddenContainer.h" -#include "SVGFilter.h" -#include "SVGFilterPrimitiveStandardAttributes.h" +#include "RenderSVGResourceFilter.h" namespace WebCore { +class FilterEffect; + class RenderSVGResourceFilterPrimitive : public RenderSVGHiddenContainer { public: - - explicit RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes* filterPrimitiveElement) + explicit RenderSVGResourceFilterPrimitive(SVGStyledElement* filterPrimitiveElement) : RenderSVGHiddenContainer(filterPrimitiveElement) { } - // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. - static FloatRect determineFilterPrimitiveSubregion(FilterEffect*, SVGFilter*); - -private: virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } virtual bool isSVGResourceFilterPrimitive() const { return true; } + + // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. + static FloatRect determineFilterPrimitiveSubregion(FilterEffect*); + + inline void primitiveAttributeChanged(const QualifiedName& attribute) + { + RenderObject* filter = parent(); + if (!filter || !filter->isSVGResourceFilter()) + return; + static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, attribute); + } }; } // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp index 2a68d92..fcad27f 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp @@ -86,11 +86,10 @@ FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& marke const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const { - AffineTransform viewportTranslation(viewportTransform()); - m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); return m_localToParentTransform; // If this class were ever given a localTransform(), then the above would read: - // return viewportTransform() * localTransform() * viewportTranslation; + // return viewportTranslation * localTransform() * viewportTransform(); } FloatPoint RenderSVGResourceMarker::referencePoint() const diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index 3a8dce9..30f72b9 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -261,18 +261,15 @@ IntSize RenderSVGRoot::borderOriginToContentBox() const AffineTransform RenderSVGRoot::localToRepaintContainerTransform(const IntPoint& parentOriginInContainer) const { - AffineTransform parentToContainer(localToParentTransform()); - return parentToContainer.translateRight(parentOriginInContainer.x(), parentOriginInContainer.y()); + return AffineTransform::translation(parentOriginInContainer.x(), parentOriginInContainer.y()) * localToParentTransform(); } const AffineTransform& RenderSVGRoot::localToParentTransform() const { IntSize parentToBorderBoxOffset = parentOriginToBorderBox(); - AffineTransform borderBoxOriginToParentOrigin(localToBorderBoxTransform()); - borderBoxOriginToParentOrigin.translateRight(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()); + m_localToParentTransform = AffineTransform::translation(parentToBorderBoxOffset.width(), parentToBorderBoxOffset.height()) * localToBorderBoxTransform(); - m_localToParentTransform = borderBoxOriginToParentOrigin; return m_localToParentTransform; } diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index dad0b70..56d9306 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -33,7 +33,7 @@ #include "GraphicsContext.h" #include "HitTestRequest.h" #include "PointerEventsHitRules.h" -#include "RenderLayer.h" +#include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGRoot.h" #include "SVGLengthList.h" @@ -91,6 +91,18 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, SVGRenderSupport::mapLocalToContainer(this, repaintContainer, fixed, useTransforms, transformState); } +static inline void recursiveUpdateScaledFont(RenderObject* start) +{ + for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + if (child->isSVGInlineText()) { + toRenderSVGInlineText(child)->updateScaledFont(); + continue; + } + + recursiveUpdateScaledFont(child); + } +} + void RenderSVGText::layout() { ASSERT(needsLayout()); @@ -104,6 +116,13 @@ void RenderSVGText::layout() updateCachedBoundariesInParents = true; } + // If the root layout size changed (eg. window size changes) or the positioning values change, recompute the on-screen font size. + if (m_needsPositioningValuesUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { + recursiveUpdateScaledFont(this); + m_needsPositioningValuesUpdate = true; + updateCachedBoundariesInParents = true; + } + if (m_needsPositioningValuesUpdate) { // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). SVGTextLayoutAttributesBuilder layoutAttributesBuilder; diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp index 7f4b6f7..0f2f273 100644 --- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp @@ -72,11 +72,10 @@ AffineTransform RenderSVGViewportContainer::viewportTransform() const const AffineTransform& RenderSVGViewportContainer::localToParentTransform() const { - AffineTransform viewportTranslation(viewportTransform()); - m_localToParentTransform = viewportTranslation.translateRight(m_viewport.x(), m_viewport.y()); + m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform(); return m_localToParentTransform; // If this class were ever given a localTransform(), then the above would read: - // return viewportTransform() * localTransform() * viewportTranslation; + // return viewportTranslation * localTransform() * viewportTransform() } bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& pointInParent) diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 2879f20..52976f2 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -30,6 +30,7 @@ #include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGResourceSolidColor.h" +#include "SVGImageBufferTools.h" #include "SVGRootInlineBox.h" #include "TextRun.h" @@ -56,9 +57,12 @@ int SVGInlineTextBox::offsetForPosition(int, bool) const int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const { - RenderText* textRenderer = this->textRenderer(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + RenderStyle* style = textRenderer->style(); ASSERT(style); @@ -69,7 +73,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen if (!fragment.transform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale())); - return fragment.positionListOffset - start() + style->font().offsetForPosition(textRun, position, includePartialGlyphs); + return fragment.positionListOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } int SVGInlineTextBox::positionForOffset(int) const @@ -82,10 +86,28 @@ int SVGInlineTextBox::positionForOffset(int) const FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& fragment, int startPosition, int endPosition, RenderStyle* style) { ASSERT(startPosition < endPosition); + ASSERT(style); + + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); - const Font& font = style->font(); - FloatPoint textOrigin(fragment.x, fragment.y - font.ascent()); - return font.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height, startPosition, endPosition); + const Font& scaledFont = textRenderer->scaledFont(); + const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); + FloatPoint textOrigin(fragment.x, fragment.y); + if (scalingFactor != 1) + textOrigin.scale(scalingFactor, scalingFactor); + + textOrigin.move(0, -scaledFontMetrics.floatAscent()); + + FloatRect selectionRect = scaledFont.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height * scalingFactor, startPosition, endPosition); + if (scalingFactor == 1) + return selectionRect; + + selectionRect.scale(1 / scalingFactor); + return selectionRect; } IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosition) @@ -125,6 +147,13 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi return enclosingIntRect(selectionRect); } +static inline bool textShouldBePainted(RenderSVGInlineText* textRenderer) +{ + // Font::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". + // If the absolute font size on screen is below x=0.5, don't render anything. + return textRenderer->scaledFont().pixelSize(); +} + void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); @@ -148,6 +177,11 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (!backgroundColor.isValid() || !backgroundColor.alpha()) return; + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + if (!textShouldBePainted(textRenderer)) + return; + RenderStyle* style = parentRenderer->style(); ASSERT(style); @@ -222,6 +256,11 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) if (!hasSelection && paintSelectedTextOnly) return; + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + if (!textShouldBePainted(textRenderer)) + return; + RenderStyle* style = parentRenderer->style(); ASSERT(style); @@ -286,8 +325,9 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int) ASSERT(!m_paintingResource); } -bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, RenderObject* renderer, RenderStyle* style) +bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderObject* renderer, RenderStyle* style) { + ASSERT(scalingFactor); ASSERT(renderer); ASSERT(style); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); @@ -315,6 +355,9 @@ bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, Render } } + if (scalingFactor != 1 && m_paintingResourceMode & ApplyToStrokeMode) + context->setStrokeThickness(context->strokeThickness() * scalingFactor); + return true; } @@ -329,9 +372,9 @@ void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const m_paintingResource = 0; } -bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, TextRun& textRun, RenderStyle* style) +bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) { - bool acquiredResource = acquirePaintingResource(context, parent()->renderer(), style); + bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); #if ENABLE(SVG_FONTS) // SVG Fonts need access to the painting resource used to draw the current text chunk. @@ -364,14 +407,12 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag , false /* allowTabs */ , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ + , TextRun::AllowTrailingExpansion , direction() == RTL , m_dirOverride || style->visuallyOrdered() /* directionalOverride */); #if ENABLE(SVG_FONTS) - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - - run.setReferencingRenderObject(parentRenderer); + run.setReferencingRenderObject(text); #endif // Disable any word/character rounding. @@ -409,16 +450,16 @@ bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGText return true; } -static inline float positionOffsetForDecoration(ETextDecoration decoration, const Font& font, float thickness) +static inline float positionOffsetForDecoration(ETextDecoration decoration, const FontMetrics& fontMetrics, float thickness) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera. if (decoration == UNDERLINE) - return font.ascent() + thickness * 1.5f; + return fontMetrics.floatAscent() + thickness * 1.5f; if (decoration == OVERLINE) return thickness; if (decoration == LINE_THROUGH) - return font.ascent() * 5.0f / 8.0f; + return fontMetrics.floatAscent() * 5 / 8.0f; ASSERT_NOT_REACHED(); return 0.0f; @@ -486,22 +527,34 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD RenderStyle* decorationStyle = decorationRenderer->style(); ASSERT(decorationStyle); - const Font& font = decorationStyle->font(); + float scalingFactor = 1; + Font scaledFont; + RenderSVGInlineText::computeNewScaledFontForStyle(decorationRenderer, decorationStyle, scalingFactor, scaledFont); + ASSERT(scalingFactor); // The initial y value refers to overline position. - float thickness = thicknessForDecoration(decoration, font); + float thickness = thicknessForDecoration(decoration, scaledFont); if (fragment.width <= 0 && thickness <= 0) return; - float y = fragment.y - font.ascent() + positionOffsetForDecoration(decoration, font, thickness); - - Path path; - path.addRect(FloatRect(fragment.x, y, fragment.width, thickness)); + FloatPoint decorationOrigin(fragment.x, fragment.y); + float width = fragment.width; + const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); context->save(); + if (scalingFactor != 1) { + width *= scalingFactor; + decorationOrigin.scale(scalingFactor, scalingFactor); + context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + } - if (acquirePaintingResource(context, decorationRenderer, decorationStyle)) + decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); + + Path path; + path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); + + if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle)) releasePaintingResource(context, &path); context->restore(); @@ -509,21 +562,41 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, ETextD void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) { - const Font& font = style->font(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + const Font& scaledFont = textRenderer->scaledFont(); const ShadowData* shadow = style->textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); - FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - font.ascent()), FloatSize(fragment.width, fragment.height)); + FloatSize textSize(fragment.width, fragment.height); + + if (scalingFactor != 1) { + textOrigin.scale(scalingFactor, scalingFactor); + textSize.scale(scalingFactor); + } + + FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); do { - if (!prepareGraphicsContextForTextPainting(context, textRun, style)) + if (!prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) break; FloatSize extraOffset; if (shadow) extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); - font.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); + if (scalingFactor != 1) + context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + + scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); + + if (scalingFactor != 1) + context->scale(FloatSize(scalingFactor, scalingFactor)); + restoreGraphicsContextAfterTextPainting(context, textRun); if (!shadow) @@ -580,19 +653,18 @@ IntRect SVGInlineTextBox::calculateBoundaries() const { FloatRect textRect; - RenderText* textRenderer = this->textRenderer(); + RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); ASSERT(textRenderer); - RenderStyle* style = textRenderer->style(); - ASSERT(style); + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); - int baseline = baselinePosition(AlphabeticBaseline); - int heightDifference = baseline - style->font().ascent(); + float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = m_textFragments.at(i); - FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height + heightDifference); + FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); if (!fragment.transform.isIdentity()) fragmentRect = fragment.transform.mapRect(fragmentRect); diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index 0458de0..f2ca303 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -66,10 +66,10 @@ public: private: TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const; - bool acquirePaintingResource(GraphicsContext*&, RenderObject*, RenderStyle*); + bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, RenderStyle*); void releasePaintingResource(GraphicsContext*&, const Path*); - bool prepareGraphicsContextForTextPainting(GraphicsContext*&, TextRun&, RenderStyle*); + bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*); void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&); void paintDecoration(GraphicsContext*, ETextDecoration, const SVGTextFragment&); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp index 3b28d2b..c25ed79 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp @@ -310,7 +310,7 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b SVGTextFragment& fragment = fragments.at(i); AffineTransform& transform = fragment.transform; if (!transform.isIdentity()) { - transform.translateRight(fragment.x, fragment.y); + transform = AffineTransform::translation(fragment.x, fragment.y) * transform; transform.translate(-fragment.x, -fragment.y); } diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 3863322..4221f26 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -49,9 +49,9 @@ float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* case BS_BASELINE: return 0; case BS_SUB: - return -m_font.height() / 2; + return -m_font.fontMetrics().floatHeight() / 2; case BS_SUPER: - return m_font.height() / 2; + return m_font.fontMetrics().floatHeight() / 2; default: ASSERT_NOT_REACHED(); return 0; @@ -122,27 +122,29 @@ float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVertic ASSERT(baseline != AB_AUTO); } + const FontMetrics& fontMetrics = m_font.fontMetrics(); + // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling switch (baseline) { case AB_BASELINE: return dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent); case AB_BEFORE_EDGE: case AB_TEXT_BEFORE_EDGE: - return m_font.ascent(); + return fontMetrics.floatAscent(); case AB_MIDDLE: - return m_font.xHeight() / 2; + return fontMetrics.xHeight() / 2; case AB_CENTRAL: - return (m_font.ascent() - m_font.descent()) / 2; + return (fontMetrics.floatAscent() - fontMetrics.floatDescent()) / 2; case AB_AFTER_EDGE: case AB_TEXT_AFTER_EDGE: case AB_IDEOGRAPHIC: - return m_font.descent(); + return fontMetrics.floatDescent(); case AB_ALPHABETIC: return 0; case AB_HANGING: - return m_font.ascent() * 8 / 10.f; + return fontMetrics.floatAscent() * 8 / 10.f; case AB_MATHEMATICAL: - return m_font.ascent() / 2; + return fontMetrics.floatAscent() / 2; default: ASSERT_NOT_REACHED(); return 0; @@ -192,12 +194,14 @@ float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVe // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of // 180 degrees, then the current text position is incremented according to the horizontal metrics of the glyph. + const FontMetrics& fontMetrics = m_font.fontMetrics(); + // Vertical orientation handling. if (isVerticalText) { - float ascentMinusDescent = m_font.ascent() - m_font.descent(); + float ascentMinusDescent = fontMetrics.floatAscent() - fontMetrics.floatDescent(); if (!angle) { xOrientationShift = (ascentMinusDescent - metrics.width()) / 2; - yOrientationShift = m_font.ascent(); + yOrientationShift = fontMetrics.floatAscent(); } else if (angle == 180) xOrientationShift = (ascentMinusDescent + metrics.width()) / 2; else if (angle == 270) { @@ -217,7 +221,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVe yOrientationShift = -metrics.width(); else if (angle == 180) { xOrientationShift = metrics.width(); - yOrientationShift = -m_font.ascent(); + yOrientationShift = -fontMetrics.floatAscent(); } else if (angle == 270) xOrientationShift = metrics.width(); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp index 6c54b67..e9aa127 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp @@ -58,7 +58,7 @@ float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const m_lastGlyph = currentGlyph; m_lastGlyph.isValid = true; - kerning *= m_font.size() / m_font.primaryFont()->unitsPerEm(); + kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); return kerning; #else UNUSED_PARAM(isVerticalText); diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp index ec8c2c6..ca20d3d 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp @@ -34,16 +34,21 @@ SVGTextMetrics::SVGTextMetrics() { } -SVGTextMetrics::SVGTextMetrics(const Font& font, const TextRun& run, unsigned position, unsigned textLength) - : m_width(0) - , m_height(0) - , m_length(0) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& run, unsigned position, unsigned textLength) { + ASSERT(textRenderer); + + float scalingFactor = textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + const Font& scaledFont = textRenderer->scaledFont(); + int extraCharsAvailable = textLength - (position + run.length()); int length = 0; - m_width = font.floatWidth(run, extraCharsAvailable, length, m_glyph.name); - m_height = font.height(); + // Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards. + m_width = scaledFont.floatWidth(run, extraCharsAvailable, length, m_glyph.name) / scalingFactor; + m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; m_glyph.unicodeString = String(run.characters(), length); m_glyph.isValid = true; @@ -71,8 +76,7 @@ static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characte TextRun run(characters + position, length); #if ENABLE(SVG_FONTS) - ASSERT(text->parent()); - run.setReferencingRenderObject(text->parent()); + run.setReferencingRenderObject(text); #endif // Disable any word/character rounding. @@ -86,18 +90,13 @@ static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characte SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length) { ASSERT(text); - ASSERT(text->style()); - TextRun run(constructTextRun(text, text->characters(), position, length)); - return SVGTextMetrics(text->style()->font(), run, position, text->textLength()); + return SVGTextMetrics(text, run, position, text->textLength()); } void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, Vector<SVGTextMetrics>& allMetrics) { ASSERT(text); - ASSERT(text->style()); - - const Font& font = text->style()->font(); const UChar* characters = text->characters(); unsigned length = text->textLength(); @@ -105,7 +104,7 @@ void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, for (unsigned position = 0; position < length; ) { run.setText(characters + position, 1); - SVGTextMetrics metrics(font, run, position, text->textLength()); + SVGTextMetrics metrics(text, run, position, text->textLength()); allMetrics.append(metrics); position += metrics.length(); } diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.h b/Source/WebCore/rendering/svg/SVGTextMetrics.h index ba18589..7ef0f7d 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.h +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.h @@ -25,7 +25,6 @@ namespace WebCore { -class Font; class RenderSVGInlineText; class TextRun; @@ -64,7 +63,7 @@ public: private: SVGTextMetrics(); - SVGTextMetrics(const Font&, const TextRun&, unsigned position, unsigned textLength); + SVGTextMetrics(RenderSVGInlineText*, const TextRun&, unsigned position, unsigned textLength); float m_width; float m_height; diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp index 42d511b..1a4cdab 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp +++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp @@ -472,7 +472,10 @@ struct ExtentOfCharacterData : SVGTextQuery::Data { static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { - extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->style()->font().ascent())); + float scalingFactor = queryData->textRenderer->scalingFactor(); + ASSERT(scalingFactor); + + extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); if (startPosition) { SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition); |