AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (attributes()->getAttributeItem(SVGNames::viewBoxAttr)) viewBoxTransform = viewBoxToViewTransform(width().value(this), height().value(this)); AffineTransform transform; if (!isOutermostSVG()) transform.translate(x().value(this), y().value(this)); else if (mode == SVGLocatable::ScreenScope) { if (RenderObject* renderer = this->renderer()) { // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. FloatPoint location = renderer->localToAbsolute(FloatPoint(), false, true); // Be careful here! localToAbsolute() includes the x/y offset coming from the viewBoxToViewTransform(), because // RenderSVGRoot::localToBorderBoxTransform() (called through mapLocalToContainer(), called from localToAbsolute()) // also takes the viewBoxToViewTransform() into account, so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document()->view()) { IntSize scrollOffset = view->scrollOffset(); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multLeft(viewBoxTransform); }
void SVGAnimateMotionElement::applyResultsToTarget() { // We accumulate to the target element transform list so there is not much to do here. SVGElement* targetElement = this->targetElement(); if (!targetElement) return; if (RenderObject* renderer = targetElement->renderer()) RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); AffineTransform* t = targetElement->supplementalTransform(); if (!t) return; // ...except in case where we have additional instances in <use> trees. const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement(); const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); ASSERT(shadowTreeElement); AffineTransform* transform = shadowTreeElement->supplementalTransform(); if (!transform) continue; transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f()); if (RenderObject* renderer = shadowTreeElement->renderer()) { renderer->setNeedsTransformUpdate(); RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); } } }
AffineTransform SVGGraphicsElement::animatedLocalTransform() const { AffineTransform matrix; RenderStyle* style = renderer() ? &renderer()->style() : nullptr; // If CSS property was set, use that, otherwise fallback to attribute (if set). if (style && style->hasTransform()) { // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath. // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/ TransformationMatrix transform; style->applyTransform(transform, renderer()->objectBoundingBox()); // Flatten any 3D transform. matrix = transform.toAffineTransform(); // CSS bakes the zoom factor into lengths, including translation components. // In order to align CSS & SVG transforms, we need to invert this operation. float zoom = style->effectiveZoom(); if (zoom != 1) { matrix.setE(matrix.e() / zoom); matrix.setF(matrix.f() / zoom); } } else transform().concatenate(matrix); if (m_supplementalTransform) return *m_supplementalTransform * matrix; return matrix; }
static void drawDeferredFilter(GraphicsContext* context, FilterData* filterData, SVGFilterElement* filterElement) { SkiaImageFilterBuilder builder(context); SourceGraphic* sourceGraphic = static_cast<SourceGraphic*>(filterData->builder->getEffectById(SourceGraphic::effectName())); ASSERT(sourceGraphic); builder.setSourceGraphic(sourceGraphic); RefPtr<ImageFilter> imageFilter = builder.build(filterData->builder->lastEffect(), ColorSpaceDeviceRGB); FloatRect boundaries = filterData->boundaries; context->save(); FloatSize deviceSize = context->getCTM().mapSize(boundaries.size()); float scaledArea = deviceSize.width() * deviceSize.height(); // If area of scaled size is bigger than the upper limit, adjust the scale // to fit. Note that this only really matters in the non-impl-side painting // case, since the impl-side case never allocates a full-sized backing // store, only tile-sized. // FIXME: remove this once all platforms are using impl-side painting. // crbug.com/169282. if (scaledArea > FilterEffect::maxFilterArea()) { float scale = sqrtf(FilterEffect::maxFilterArea() / scaledArea); context->scale(scale, scale); } // Clip drawing of filtered image to the minimum required paint rect. FilterEffect* lastEffect = filterData->builder->lastEffect(); context->clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect())); if (filterElement->hasAttribute(SVGNames::filterResAttr)) { // Get boundaries in device coords. // FIXME: See crbug.com/382491. Is the use of getCTM OK here, given it does not include device // zoom or High DPI adjustments? FloatSize size = context->getCTM().mapSize(boundaries.size()); // Compute the scale amount required so that the resulting offscreen is exactly filterResX by filterResY pixels. float filterResScaleX = filterElement->filterResX()->currentValue()->value() / size.width(); float filterResScaleY = filterElement->filterResY()->currentValue()->value() / size.height(); // Scale the CTM so the primitive is drawn to filterRes. context->scale(filterResScaleX, filterResScaleY); // Create a resize filter with the inverse scale. AffineTransform resizeMatrix; resizeMatrix.scale(1 / filterResScaleX, 1 / filterResScaleY); imageFilter = builder.buildTransform(resizeMatrix, imageFilter.get()); } // If the CTM contains rotation or shearing, apply the filter to // the unsheared/unrotated matrix, and do the shearing/rotation // as a final pass. AffineTransform ctm = context->getCTM(); if (ctm.b() || ctm.c()) { AffineTransform scaleAndTranslate; scaleAndTranslate.translate(ctm.e(), ctm.f()); scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); ASSERT(scaleAndTranslate.isInvertible()); AffineTransform shearAndRotate = scaleAndTranslate.inverse(); shearAndRotate.multiply(ctm); context->setCTM(scaleAndTranslate); imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); } context->beginLayer(1, CompositeSourceOver, &boundaries, ColorFilterNone, imageFilter.get()); context->endLayer(); context->restore(); }
static v8::Handle<v8::Value> fAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.AffineTransform.f._get"); V8SVGPODTypeWrapper<AffineTransform>* impWrapper = V8SVGPODTypeWrapper<AffineTransform>::toNative(info.Holder()); AffineTransform impInstance = *impWrapper; AffineTransform* imp = &impInstance; return v8::Number::New(imp->f()); }
// static void Shader::affineTo3x3(const AffineTransform& transform, float mat[9]) { mat[0] = transform.a(); mat[1] = transform.b(); mat[2] = 0.0f; mat[3] = transform.c(); mat[4] = transform.d(); mat[5] = 0.0f; mat[6] = transform.e(); mat[7] = transform.f(); mat[8] = 1.0f; }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform( SVGElement::CTMScope mode) const { AffineTransform viewBoxTransform; if (!hasEmptyViewBox()) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)); } else if (mode == SVGElement::ScreenScope) { if (LayoutObject* layoutObject = this->layoutObject()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the // localToBorderBoxTransform to map an element from SVG viewport // coordinates to CSS box coordinates. LayoutSVGRoot's localToAbsolute // method expects CSS box coordinates. We also need to adjust for the // zoom level factored into CSS coordinates (bug #96361). if (layoutObject->isSVGRoot()) { location = toLayoutSVGRoot(layoutObject) ->localToBorderBoxTransform() .mapPoint(location); zoomFactor = 1 / layoutObject->style()->effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = layoutObject->localToAbsolute(location, UseTransforms); location.scale(zoomFactor, zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset // coming from the viewBoxToViewTransform(), so we have to subtract it // here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document().view()) { LayoutSize scrollOffset(view->getScrollOffset()); scrollOffset.scale(zoomFactor); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (!hasEmptyViewBox()) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(x().value(lengthContext), y().value(lengthContext)); } else if (mode == SVGLocatable::ScreenScope) { if (auto* renderer = this->renderer()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates. // We also need to adjust for the zoom level factored into CSS coordinates (bug #96361). if (is<RenderSVGRoot>(*renderer)) { location = downcast<RenderSVGRoot>(*renderer).localToBorderBoxTransform().mapPoint(location); zoomFactor = 1 / renderer->style().effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = renderer->localToAbsolute(location, UseTransforms); location.scale(zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(), // so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document().view()) { LayoutPoint scrollPosition = view->scrollPosition(); scrollPosition.scale(zoomFactor); transform.translate(-scrollPosition.x(), -scrollPosition.y()); } } } return transform.multiply(viewBoxTransform); }
SkMatrix affineTransformToSkMatrix(const AffineTransform& source) { SkMatrix result; result.setScaleX(WebCoreDoubleToSkScalar(source.a())); result.setSkewX(WebCoreDoubleToSkScalar(source.c())); result.setTranslateX(WebCoreDoubleToSkScalar(source.e())); result.setScaleY(WebCoreDoubleToSkScalar(source.d())); result.setSkewY(WebCoreDoubleToSkScalar(source.b())); result.setTranslateY(WebCoreDoubleToSkScalar(source.f())); // FIXME: Set perspective properly. result.setPerspX(0); result.setPerspY(0); result.set(SkMatrix::kMPersp2, SK_Scalar1); return result; }
static void paintFilteredContent(const LayoutObject& object, GraphicsContext& context, FilterData* filterData) { ASSERT(filterData->m_state == FilterData::ReadyToPaint); ASSERT(filterData->filter->sourceGraphic()); filterData->m_state = FilterData::PaintingFilter; SkiaImageFilterBuilder builder; RefPtr<SkImageFilter> imageFilter = builder.build(filterData->filter->lastEffect(), ColorSpaceDeviceRGB); FloatRect boundaries = filterData->filter->filterRegion(); context.save(); // Clip drawing of filtered image to the minimum required paint rect. FilterEffect* lastEffect = filterData->filter->lastEffect(); context.clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect())); #ifdef CHECK_CTM_FOR_TRANSFORMED_IMAGEFILTER // TODO: Remove this workaround once skew/rotation support is added in Skia // (https://code.google.com/p/skia/issues/detail?id=3288, crbug.com/446935). // If the CTM contains rotation or shearing, apply the filter to // the unsheared/unrotated matrix, and do the shearing/rotation // as a final pass. AffineTransform ctm = SVGLayoutSupport::deprecatedCalculateTransformToLayer(&object); if (ctm.b() || ctm.c()) { AffineTransform scaleAndTranslate; scaleAndTranslate.translate(ctm.e(), ctm.f()); scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); ASSERT(scaleAndTranslate.isInvertible()); AffineTransform shearAndRotate = scaleAndTranslate.inverse(); shearAndRotate.multiply(ctm); context.concatCTM(shearAndRotate.inverse()); imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); } #endif context.beginLayer(1, SkXfermode::kSrcOver_Mode, &boundaries, ColorFilterNone, imageFilter.get()); context.endLayer(); context.restore(); filterData->m_state = FilterData::ReadyToPaint; }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (hasAttribute(SVGNames::viewBoxAttr)) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(x().value(lengthContext), y().value(lengthContext)); } else if (mode == SVGLocatable::ScreenScope) { if (RenderObject* renderer = this->renderer()) { FloatPoint location; // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates. if (renderer->isSVGRoot()) location = toRenderSVGRoot(renderer)->localToBorderBoxTransform().mapPoint(location); // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = renderer->localToAbsolute(location, false, true); // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(), // so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document()->view()) { LayoutSize scrollOffset = view->scrollOffset(); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
static inline void normalizeTransform(AffineTransform& transform) { // Obtain consistent numerical results for the AffineTransform on both 32/64bit platforms. // Tested with SnowLeopard on Core Duo vs. Core 2 Duo. static const float s_floatEpsilon = std::numeric_limits<float>::epsilon(); if (fabs(transform.a() - 1) <= s_floatEpsilon) transform.setA(1); else if (fabs(transform.a() + 1) <= s_floatEpsilon) transform.setA(-1); if (fabs(transform.d() - 1) <= s_floatEpsilon) transform.setD(1); else if (fabs(transform.d() + 1) <= s_floatEpsilon) transform.setD(-1); if (fabs(transform.e()) <= s_floatEpsilon) transform.setE(0); if (fabs(transform.f()) <= s_floatEpsilon) transform.setF(0); }
String SVGTransformList::valueAsString() const { // TODO: We may want to build a real transform string, instead of concatting to a matrix(...). SVGTransform transform = concatenate(); if (transform.type() == SVGTransform::SVG_TRANSFORM_MATRIX) { AffineTransform matrix = transform.matrix(); return String::format("matrix(%f %f %f %f %f %f)", matrix.a(), matrix.b(), matrix.c(), matrix.d(), matrix.e(), matrix.f()); } return String(); }
bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); #ifndef NDEBUG ASSERT(resourceMode == ApplyToDefaultMode); #else UNUSED_PARAM(resourceMode); #endif // Returning false here, to avoid drawings onto the context. We just want to // draw the stored filter output, not the unfiltered object as well. if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->builded) return false; delete m_filter.take(object); // Oops, have to rebuild, go through normal code path } OwnPtr<FilterData> filterData(new FilterData); FloatRect targetBoundingBox = object->objectBoundingBox(); SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); filterData->boundaries = filterElement->filterBoundingBox(targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); if (!absoluteTransform.isInvertible()) return false; // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), absoluteTransform.e(), absoluteTransform.f()); // Determine absolute boundaries of the filter and the drawing region. FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); FloatRect drawingRegion = object->strokeBoundingBox(); drawingRegion.intersect(filterData->boundaries); FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion); // Create the SVGFilter object. bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. filterData->builder = buildPrimitives(filterData->filter.get()); if (!filterData->builder) return false; // Calculate the scale factor for the use of filterRes. // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion FloatSize scale(1, 1); if (filterElement->hasAttribute(SVGNames::filterResAttr)) { scale.setWidth(filterElement->filterResX() / absoluteFilterBoundaries.width()); scale.setHeight(filterElement->filterResY() / absoluteFilterBoundaries.height()); } if (scale.isEmpty()) return false; // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. FloatRect tempSourceRect = absoluteDrawingRegion; tempSourceRect.scale(scale.width(), scale.height()); fitsInMaximumImageSize(tempSourceRect.size(), scale); // Set the scale level in SVGFilter. filterData->filter->setFilterResolution(scale); FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect, filterData->filter.get()); 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()); } // If the drawingRegion is empty, we have something like <g filter=".."/>. // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource. if (drawingRegion.isEmpty()) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.leakPtr()); return false; } absoluteDrawingRegion.scale(scale.width(), scale.height()); OwnPtr<ImageBuffer> sourceGraphic; if (!SVGImageBufferTools::createImageBuffer(absoluteDrawingRegion, absoluteDrawingRegion, sourceGraphic, ColorSpaceLinearRGB)) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.leakPtr()); return false; } GraphicsContext* sourceGraphicContext = sourceGraphic->context(); ASSERT(sourceGraphicContext); sourceGraphicContext->translate(-absoluteDrawingRegion.x(), -absoluteDrawingRegion.y()); if (scale.width() != 1 || scale.height() != 1) sourceGraphicContext->scale(scale); sourceGraphicContext->concatCTM(filterData->shearFreeAbsoluteTransform); sourceGraphicContext->clearRect(FloatRect(FloatPoint(), absoluteDrawingRegion.size())); filterData->sourceGraphicBuffer = sourceGraphic.release(); filterData->savedContext = context; context = sourceGraphicContext; ASSERT(!m_filter.contains(object)); m_filter.set(object, filterData.leakPtr()); return true; }
IntRect RenderSVGInlineText::computeAbsoluteRectForRange(int startPos, int endPos) { IntRect rect; RenderBlock* cb = containingBlock(); if (!cb || !cb->container()) return rect; RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) return rect; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) rect.unite(box->selectionRect(0, 0, startPos, endPos)); // Mimic RenderBox::computeAbsoluteRepaintRect() functionality. But only the subset needed for SVG and respecting SVG transformations. int x, y; cb->container()->absolutePosition(x, y); // Remove HTML parent translation offsets here! These need to be retrieved from the RenderSVGRoot object. // But do take the containingBlocks's container position into account, ie. SVG text in scrollable <div>. AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform(); FloatRect fixedRect(narrowPrecisionToFloat(rect.x() + x - xPos() - htmlParentCtm.e()), narrowPrecisionToFloat(rect.y() + y - yPos() - htmlParentCtm.f()), rect.width(), rect.height()); return enclosingIntRect(absoluteTransform().mapRect(fixedRect)); }
void GraphicsContext::concatCTM(const AffineTransform& affine) { if (paintingDisabled()) return; //platformContext()->canvas()->concat(affine); nvgTransform(platformContext()->canvas(), affine.a(), affine.b(), affine.c(), affine.d(), affine.e(), affine.f()); }
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); // FIXME: use fallback fonts as well? Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); adjustOffsetsForTextDrawing(run, from, to); SurfaceOpenVG* surface = context->platformContext(); surface->makeCurrent(); // Before passing control to Text API, make sure we're ok ourselves. ASSERT_VG_NO_ERROR(); PainterOpenVG* painter = surface->activePainter(); painter->save(); painter->setStateModified(PainterOpenVG::AllStateCategories); Olympia::Platform::Text::GraphicsContext* textContext = FontPlatformData::textGraphicsContext(); #if PLATFORM(EGL) textContext->setDisplay(static_cast<Olympia::Platform::Text::NativeGraphicsDisplay>(surface->eglDisplay())); textContext->setSurface(static_cast<Olympia::Platform::Text::NativeGraphicsSurface>(surface->eglSurface())); textContext->setContext(static_cast<Olympia::Platform::Text::NativeGraphicsContext>(surface->eglContext())); ASSERT_EGL_NO_ERROR(); #endif if (painter->textDrawingMode() & cTextClip) return; // unsupported for every port except CG at the time of writing if (!(painter->textDrawingMode() & cTextFill)) painter->setFillColor(Color::transparent); if (!(painter->textDrawingMode() & cTextStroke)) painter->setStrokeStyle(NoStroke); if (from > 0 || to < sanitized.length()) { // Clip to the from-to region. We need to draw the full text // (and clip) because characters might change appearance when // connected to other characters. double fromX; FontPlatformData::engine()->textPosToX(from, fromX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); fromX *= scaleFactor; double toX; FontPlatformData::engine()->textPosToX(to, toX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); toX *= scaleFactor; // FIXME: Some glyphs can be higher than primary font's height. // We multiply ascent and descent by 4 so the clip rect will be high // enough for all glyphs we know. This is safe because we only apply // the clip rect when drawing partial strings, and we are only interested // in horizontal clip range. const float y = point.y() - primaryFont()->ascent() * 4; const float height = (primaryFont()->ascent() + primaryFont()->descent()) * 4; FloatRect clipRect = (toX > fromX) ? FloatRect(point.x() + fromX, y, toX - fromX, height) : FloatRect(point.x() + toX, y, fromX - toX, height); painter->clipRect(clipRect, PainterOpenVG::IntersectClip); } AffineTransform transformation = painter->transformation(); transformation.translate(point.x(), point.y()); FloatPoint currentTranslation(transformation.e(), transformation.f()); transformation.setE(0); transformation.setF(0); transformation.scale(scaleFactor); transformation.setE(roundf(currentTranslation.x())); transformation.setF(roundf(currentTranslation.y())); painter->setTransformation(transformation); if (painter->shadowEnabled()) { painter->beginDrawShadow(); FontPlatformData::engine()->drawText(textContext, *font, sanitized.characters(), sanitized.length(), 0, 0, 0 /* no wrap */, &drawParam, 0 /* returned metrics */); painter->endDrawShadow(); } FontPlatformData::engine()->drawText(textContext, *font, sanitized.characters(), sanitized.length(), 0, 0, 0 /* no wrap */, &drawParam, 0 /* returned metrics */); #if PLATFORM(EGL) SurfaceOpenVG* sharedSurface = surface->sharedSurface(); textContext->setDisplay(static_cast<Olympia::Platform::Text::NativeGraphicsDisplay>(sharedSurface->eglDisplay())); textContext->setSurface(static_cast<Olympia::Platform::Text::NativeGraphicsSurface>(sharedSurface->eglSurface())); textContext->setContext(static_cast<Olympia::Platform::Text::NativeGraphicsContext>(sharedSurface->eglContext())); ASSERT_EGL_NO_ERROR(); #endif // Let's make sure Text API didn't cause any troubles. ASSERT_VG_NO_ERROR(); painter->restore(); }
void RenderSVGText::absoluteRects(Vector<IntRect>& rects, int, int, bool) { RenderSVGRoot* root = findSVGRootObject(parent()); if (!root) return; int x, y; absolutePosition(x, y); AffineTransform htmlParentCtm = root->RenderContainer::absoluteTransform(); // Don't use relativeBBox here, as it's unites the selection rects. Makes it hard // to spot errors, if there are any using WebInspector. Individually feed them into 'rects'. for (InlineRunBox* runBox = firstLineBox(); runBox; runBox = runBox->nextLineBox()) { ASSERT(runBox->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(runBox); for (InlineBox* box = flowBox->firstChild(); box; box = box->nextOnLine()) { FloatRect boxRect(box->xPos(), box->yPos(), box->width(), box->height()); boxRect.move(narrowPrecisionToFloat(x - htmlParentCtm.e()), narrowPrecisionToFloat(y - htmlParentCtm.f())); rects.append(enclosingIntRect(absoluteTransform().mapRect(boxRect))); } } }