Ejemplo n.º 1
0
void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle penStyle)
{
    // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic
    // works out.  For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g.,
    // (50+53)/2 = 103/2 = 51 when we want 51.5.  It is always true that an even width gave
    // us a perfect position, but an odd width gave us a position that is off by exactly 0.5.
    if (penStyle == DottedStroke || penStyle == DashedStroke) {
        if (p1.x() == p2.x()) {
            p1.setY(p1.y() + strokeWidth);
            p2.setY(p2.y() - strokeWidth);
        } else {
            p1.setX(p1.x() + strokeWidth);
            p2.setX(p2.x() - strokeWidth);
        }
    }

    if (static_cast<int>(strokeWidth) % 2) { //odd
        if (p1.x() == p2.x()) {
            // We're a vertical line.  Adjust our x.
            p1.setX(p1.x() + 0.5f);
            p2.setX(p2.x() + 0.5f);
        } else {
            // We're a horizontal line. Adjust our y.
            p1.setY(p1.y() + 0.5f);
            p2.setY(p2.y() + 0.5f);
        }
    }
}
Ejemplo n.º 2
0
bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection) 
{
    float pOffset = 0;
    float pSlope = findSlope(p1, p2, pOffset);

    float dOffset = 0;
    float dSlope = findSlope(d1, d2, dOffset);

    if (dSlope == pSlope)
        return false;
    
    if (pSlope == std::numeric_limits<float>::infinity()) {
        intersection.setX(p1.x());
        intersection.setY(dSlope * intersection.x() + dOffset);
        return true;
    }
    if (dSlope == std::numeric_limits<float>::infinity()) {
        intersection.setX(d1.x());
        intersection.setY(pSlope * intersection.x() + pOffset);
        return true;
    }
    
    // Find x at intersection, where ys overlap; x = (c' - c) / (m - m')
    intersection.setX((dOffset - pOffset) / (pSlope - dSlope));
    intersection.setY(pSlope * intersection.x() + pOffset);
    return true;
}
Ejemplo n.º 3
0
FloatPoint floatPointForCenterCoordinate(const BasicShapeCenterCoordinate& centerX, const BasicShapeCenterCoordinate& centerY, FloatSize boxSize)
{
    FloatPoint p;
    float offset = floatValueForLength(centerX.length(), boxSize.width());
    switch (centerX.keyword()) {
    case BasicShapeCenterCoordinate::None:
    case BasicShapeCenterCoordinate::Left:
        p.setX(offset);
        break;
    case BasicShapeCenterCoordinate::Right:
        p.setX(boxSize.width() - offset);
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    offset = floatValueForLength(centerY.length(), boxSize.height());
    switch (centerY.keyword()) {
    case BasicShapeCenterCoordinate::None:
    case BasicShapeCenterCoordinate::Top:
        p.setY(offset);
        break;
    case BasicShapeCenterCoordinate::Bottom:
        p.setY(boxSize.height() - offset);
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    return p;
}
Ejemplo n.º 4
0
// Adjusts 'point' to the nearest point inside rect, and leaves it unchanged if already inside.
void adjustPointToRect(FloatPoint& point, const FloatRect& rect)
{
    if (point.x() < rect.x())
        point.setX(rect.x());
    else if (point.x() > rect.maxX())
        point.setX(rect.maxX());

    if (point.y() < rect.y())
        point.setY(rect.y());
    else if (point.y() > rect.maxY())
        point.setY(rect.maxY());
}
Ejemplo n.º 5
0
FloatPoint CSSGradientValue::resolvePoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, const IntSize& size, float zoomFactor)
{
    FloatPoint result;
    if (first->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
        result.setX(first->getFloatValue() * zoomFactor);
    else if (first->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
        result.setX(first->getFloatValue() / 100.f * size.width());
    if (second->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
        result.setY(second->getFloatValue() * zoomFactor);
    else if (second->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
        result.setY(second->getFloatValue() / 100.f * size.height());

    return result;
}
Ejemplo n.º 6
0
static void updateCurrentPoint(FloatPoint& currentPoint, const PathSegmentData& segment)
{
    switch (segment.command) {
    case PathSegMoveToRel:
    case PathSegLineToRel:
    case PathSegCurveToCubicRel:
    case PathSegCurveToQuadraticRel:
    case PathSegArcRel:
    case PathSegLineToHorizontalRel:
    case PathSegLineToVerticalRel:
    case PathSegCurveToCubicSmoothRel:
    case PathSegCurveToQuadraticSmoothRel:
        currentPoint += segment.targetPoint;
        break;
    case PathSegMoveToAbs:
    case PathSegLineToAbs:
    case PathSegCurveToCubicAbs:
    case PathSegCurveToQuadraticAbs:
    case PathSegArcAbs:
    case PathSegCurveToCubicSmoothAbs:
    case PathSegCurveToQuadraticSmoothAbs:
        currentPoint = segment.targetPoint;
        break;
    case PathSegLineToHorizontalAbs:
        currentPoint.setX(segment.targetPoint.x());
        break;
    case PathSegLineToVerticalAbs:
        currentPoint.setY(segment.targetPoint.y());
        break;
    case PathSegClosePath:
        break;
    default:
        ASSERT_NOT_REACHED();
    }
}
void FullscreenVideoController::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer) 
{
    ASSERT_ARG(layer, layer == m_parent->m_rootChild);

    HTMLVideoElement* videoElement = m_parent->m_videoElement.get();
    if (!videoElement)
        return;


    PlatformCALayer* videoLayer = PlatformCALayer::platformCALayer(videoElement->platformLayer());
    if (!videoLayer || videoLayer->superlayer() != layer)
        return;

    FloatRect layerBounds = layer->bounds();

    FloatSize videoSize = videoElement->player()->naturalSize();
    float scaleFactor;
    if (videoSize.aspectRatio() > layerBounds.size().aspectRatio())
        scaleFactor = layerBounds.width() / videoSize.width();
    else
        scaleFactor = layerBounds.height() / videoSize.height();
    videoSize.scale(scaleFactor);

    // Calculate the centered position based on the videoBounds and layerBounds:
    FloatPoint videoPosition;
    FloatPoint videoOrigin;
    videoOrigin.setX((layerBounds.width() - videoSize.width()) * 0.5);
    videoOrigin.setY((layerBounds.height() - videoSize.height()) * 0.5);
    videoLayer->setPosition(videoOrigin);
    videoLayer->setBounds(FloatRect(FloatPoint(), videoSize));
}
void SVGGlyphToPathTranslator::advance()
{
    do {
        if (m_glyph) {
            float advance = m_glyphBuffer.advanceAt(m_index).width();
            if (m_isVerticalText)
                m_currentPoint.move(0, advance);
            else
                m_currentPoint.move(advance, 0);
        }

        ++m_index;
        if (m_index >= m_stoppingPoint || !m_glyphBuffer.fontDataAt(m_index)->isSVGFont())
            break;
        m_glyph = m_glyphBuffer.glyphAt(m_index);
        if (!m_glyph)
            continue;
        m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
        ASSERT(!m_svgGlyph.isPartOfLigature);
        ASSERT(m_svgGlyph.tableEntry == m_glyph);
        SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
    } while ((!m_glyph || m_svgGlyph.pathData.isEmpty()) && m_index < m_stoppingPoint);

    if (containsMorePaths() && m_isVerticalText) {
        m_glyphOrigin.setX(m_svgGlyph.verticalOriginX * m_scale);
        m_glyphOrigin.setY(m_svgGlyph.verticalOriginY * m_scale);
    }
}
Ejemplo n.º 9
0
static float squaredDistanceToClosestPoint(const FloatRect& rect, const FloatPoint& point)
{
    FloatPoint closestPoint;
    closestPoint.setX(std::max(std::min(point.x(), rect.maxX()), rect.x()));
    closestPoint.setY(std::max(std::min(point.y(), rect.maxY()), rect.y()));
    return (point - closestPoint).diagonalLengthSquared();
}
Ejemplo n.º 10
0
FloatPoint ShapeOutsideInfo::shapeToRendererPoint(FloatPoint point) const
{
    FloatPoint result = FloatPoint(point.x() + logicalLeftOffset(), point.y() + logicalTopOffset());
    if (m_renderer.style()->isFlippedBlocksWritingMode())
        result.setY(m_renderer.logicalHeight() - result.y());
    if (!m_renderer.style()->isHorizontalWritingMode())
        result = result.transposedPoint();
    return result;
}
Ejemplo n.º 11
0
FloatPoint RenderSlider::mouseEventOffsetToThumb(MouseEvent* evt)
{
    ASSERT(m_thumb && m_thumb->renderer());
    FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true);
    IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
    FloatPoint offset;
    offset.setX(thumbBounds.x() + thumbBounds.width() / 2 - localPoint.x());
    offset.setY(thumbBounds.y() + thumbBounds.height() / 2 - localPoint.y());
    return offset;
}
Ejemplo n.º 12
0
void SliderThumbElement::defaultEventHandler(Event* event)
{
    if (!event->isMouseEvent()) {
        HTMLDivElement::defaultEventHandler(event);
        return;
    }

    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
    bool isLeftButton = mouseEvent->button() == LeftButton;
    const AtomicString& eventType = event->type();

    if (eventType == eventNames().mousedownEvent && isLeftButton) {
        if (document()->frame() && renderer()) {
            RenderSlider* slider = toRenderSlider(renderer()->parent());
            if (slider) {
                if (slider->mouseEventIsInThumb(mouseEvent)) {
                    // We selected the thumb, we want the cursor to always stay at
                    // the same position relative to the thumb.
                    m_offsetToThumb = slider->mouseEventOffsetToThumb(mouseEvent);
                } else {
                    // We are outside the thumb, move the thumb to the point were
                    // we clicked. We'll be exactly at the center of the thumb.
                    m_offsetToThumb.setX(0);
                    m_offsetToThumb.setY(0);
                }

                m_inDragMode = true;
                document()->frame()->eventHandler()->setCapturingMouseEventsNode(m_shadowParent);
                event->setDefaultHandled();
                return;
            }
        }
    } else if (eventType == eventNames().mouseupEvent && isLeftButton) {
        if (m_inDragMode) {
            if (Frame* frame = document()->frame())
                frame->eventHandler()->setCapturingMouseEventsNode(0);      
            m_inDragMode = false;
            event->setDefaultHandled();
            return;
        }
    } else if (eventType == eventNames().mousemoveEvent) {
        if (m_inDragMode && renderer() && renderer()->parent()) {
            RenderSlider* slider = toRenderSlider(renderer()->parent());
            if (slider) {
                FloatPoint curPoint = slider->absoluteToLocal(mouseEvent->absoluteLocation(), false, true);
                IntPoint eventOffset(curPoint.x() + m_offsetToThumb.x(), curPoint.y() + m_offsetToThumb.y());
                slider->setValueForPosition(slider->positionForOffset(eventOffset));
                event->setDefaultHandled();
                return;
            }
        }
    }

    HTMLDivElement::defaultEventHandler(event);
}
Ejemplo n.º 13
0
static void yAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.SVGPoint.y._set");
    V8SVGPODTypeWrapper<FloatPoint>* wrapper = V8SVGPODTypeWrapper<FloatPoint>::toNative(info.Holder());
    FloatPoint impInstance = *wrapper;
    FloatPoint* imp = &impInstance;
    float v = static_cast<float>(value->NumberValue());
    imp->setY(v);
    wrapper->commitChange(*imp, V8Proxy::svgContext(wrapper));
    return;
}
Ejemplo n.º 14
0
static inline FloatPoint rightMostCornerToVector(const FloatRect& rect, const FloatSize& vector)
{
    // Return the corner of the rectangle that if it is to the left of the vector
    // would mean all of the rectangle is to the left of the vector.
    // The vector here represents the side between two points in a clockwise convex polygon.
    //
    //  Q  XXX
    // QQQ XXX   If the lower left corner of X is left of the vector that goes from the top corner of Q to
    //  QQQ      the right corner of Q, then all of X is left of the vector, and intersection impossible.
    //   Q
    //
    FloatPoint point;
    if (vector.width() >= 0)
        point.setY(rect.maxY());
    else
        point.setY(rect.y());
    if (vector.height() >= 0)
        point.setX(rect.x());
    else
        point.setX(rect.maxX());
    return point;
}
Ejemplo n.º 15
0
FloatPoint Path::currentPoint() const {
  if (m_path.countPoints() > 0) {
    SkPoint skResult;
    m_path.getLastPt(&skResult);
    FloatPoint result;
    result.setX(SkScalarToFloat(skResult.fX));
    result.setY(SkScalarToFloat(skResult.fY));
    return result;
  }

  // FIXME: Why does this return quietNaN? Other ports return 0,0.
  float quietNaN = std::numeric_limits<float>::quiet_NaN();
  return FloatPoint(quietNaN, quietNaN);
}
Ejemplo n.º 16
0
Path SVGGlyphToPathTranslator::nextPath()
{
    if (m_isVerticalText) {
        m_glyphOrigin.setX(m_svgGlyph.verticalOriginX * m_scale);
        m_glyphOrigin.setY(m_svgGlyph.verticalOriginY * m_scale);
    }

    AffineTransform glyphPathTransform;
    glyphPathTransform.translate(m_currentPoint.x() + m_glyphOrigin.x(), m_currentPoint.y() + m_glyphOrigin.y());
    glyphPathTransform.scale(m_scale, -m_scale);

    Path glyphPath = m_svgGlyph.pathData;
    glyphPath.transform(glyphPathTransform);
    incrementIndex();
    return glyphPath;
}
Ejemplo n.º 17
0
bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
{
    FloatRect floatBounds = bounds;
    FloatPoint transformOrigin;
    
    bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin();
    if (applyTransformOrigin) {
        float offsetX = style.transformOriginX().isPercent() ? rendererBox.x() : 0;
        float offsetY = style.transformOriginY().isPercent() ? rendererBox.y() : 0;

        transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX);
        transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY);
        // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms.
        
        floatBounds.moveBy(-transformOrigin);
    }

    for (const auto& operation : style.transform().operations()) {
        if (operation->type() == TransformOperation::ROTATE) {
            // For now, just treat this as a full rotation. This could take angle into account to reduce inflation.
            floatBounds = boundsOfRotatingRect(floatBounds);
        } else {
            TransformationMatrix transform;
            operation->apply(transform, rendererBox.size());
            if (!transform.isAffine())
                return false;

            if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) {
                TransformationMatrix::Decomposed2Type toDecomp;
                transform.decompose2(toDecomp);
                // Any rotation prevents us from using a simple start/end rect union.
                if (toDecomp.angle)
                    return false;
            }

            floatBounds = transform.mapRect(floatBounds);
        }
    }

    if (applyTransformOrigin)
        floatBounds.moveBy(transformOrigin);

    bounds = LayoutRect(floatBounds);
    return true;
}
Ejemplo n.º 18
0
bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection)
{
    float pxLength = p2.x() - p1.x();
    float pyLength = p2.y() - p1.y();

    float dxLength = d2.x() - d1.x();
    float dyLength = d2.y() - d1.y();

    float denom = pxLength * dyLength - pyLength * dxLength;
    if (!denom)
        return false;

    float param = ((d1.x() - p1.x()) * dyLength - (d1.y() - p1.y()) * dxLength) / denom;

    intersection.setX(p1.x() + param * pxLength);
    intersection.setY(p1.y() + param * pyLength);
    return true;
}
void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (paintInfo.phase != PaintPhaseForeground)
        return;

    RenderStyle& style = flow.style();
    if (style.visibility() != VISIBLE)
        return;

    RenderText& textRenderer = toRenderText(*flow.firstChild());
    ASSERT(!textRenderer.firstTextBox());

    bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled();

    GraphicsContext& context = *paintInfo.context;

    const Font& font = style.font();
    TextPaintStyle textPaintStyle = computeTextPaintStyle(textRenderer, style, paintInfo);
    GraphicsContextStateSaver stateSaver(context, textPaintStyle.strokeWidth > 0);

    updateGraphicsContext(context, textPaintStyle);
    LayoutRect paintRect = paintInfo.rect;
    paintRect.moveBy(-paintOffset);

    auto resolver = runResolver(flow, layout);
    auto range = resolver.rangeForRect(paintRect);
    for (auto it = range.begin(), end = range.end(); it != end; ++it) {
        const auto& run = *it;
        if (!run.rect().intersects(paintRect))
            continue;
        TextRun textRun(run.text());
        textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
        FloatPoint textOrigin = run.baseline() + paintOffset;
        textOrigin.setY(roundToDevicePixel(LayoutUnit(textOrigin.y()), flow.document().deviceScaleFactor()));
        context.drawText(font, textRun, textOrigin);
        if (debugBordersEnabled)
            paintDebugBorders(context, run.rect(), paintOffset);
    }
}
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
    if (!fontElement || !fontFaceElement)
        return;

    // We can only paint SVGFonts if a context is available.
    RenderObject* renderObject = renderObjectFromRun(run);
    ASSERT(renderObject);

    bool isVerticalText = false;
    if (RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject)) {
        RenderStyle* parentRenderObjectStyle = parentRenderObject->style();
        ASSERT(parentRenderObjectStyle);
        isVerticalText = parentRenderObjectStyle->svgStyle().isVerticalWritingMode();
    }

    float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());

    FloatPoint glyphOrigin;
    glyphOrigin.setX(svgFontData->horizontalOriginX() * scale);
    glyphOrigin.setY(svgFontData->horizontalOriginY() * scale);

    unsigned short resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;

    FloatPoint currentPoint = point;
    for (int i = 0; i < numGlyphs; ++i) {
        Glyph glyph = glyphBuffer.glyphAt(from + i);
        if (!glyph)
            continue;

        float advance = glyphBuffer.advanceAt(from + i);
        SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
        ASSERT(!svgGlyph.isPartOfLigature);
        ASSERT(svgGlyph.tableEntry == glyph);

        SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData);

        // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
        if (svgGlyph.pathData.isEmpty()) {
            if (isVerticalText)
                currentPoint.move(0, advance);
            else
                currentPoint.move(advance, 0);
            continue;
         }

        if (isVerticalText) {
            glyphOrigin.setX(svgGlyph.verticalOriginX * scale);
            glyphOrigin.setY(svgGlyph.verticalOriginY * scale);
         }

        AffineTransform glyphPathTransform;
        glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
        glyphPathTransform.scale(scale, -scale);

        Path glyphPath = svgGlyph.pathData;
        glyphPath.transform(glyphPathTransform);

        SVGRenderSupport::fillOrStrokePath(context, resourceMode, glyphPath);

        if (isVerticalText)
            currentPoint.move(0, advance);
        else
            currentPoint.move(advance, 0);
    }
}
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
    if (!fontElement || !fontFaceElement)
        return;

    // We can only paint SVGFonts if a context is available.
    RenderSVGResource* activePaintingResource = activePaintingResourceFromRun(run);
    RenderObject* renderObject = renderObjectFromRun(run);
    RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject);
    RenderStyle* parentRenderObjectStyle = 0;

    ASSERT(renderObject);
    if (!activePaintingResource) {
        // TODO: We're only supporting simple filled HTML text so far.
        RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource();
        solidPaintingResource->setColor(context->fillColor());
        activePaintingResource = solidPaintingResource;
    }
 
    bool isVerticalText = false;
    if (parentRenderObject) {
        parentRenderObjectStyle = parentRenderObject->style();
        ASSERT(parentRenderObjectStyle);
        isVerticalText = parentRenderObjectStyle->svgStyle()->isVerticalWritingMode();
    }

    float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());
    ASSERT(activePaintingResource);

    FloatPoint glyphOrigin;
    glyphOrigin.setX(svgFontData->horizontalOriginX() * scale);
    glyphOrigin.setY(svgFontData->horizontalOriginY() * scale);

    FloatPoint currentPoint = point;
    RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;
    for (int i = 0; i < numGlyphs; ++i) {
        Glyph glyph = glyphBuffer.glyphAt(from + i);
        if (!glyph)
            continue;

        float advance = glyphBuffer.advanceAt(from + i);
        SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
        ASSERT(!svgGlyph.isPartOfLigature);
        ASSERT(svgGlyph.tableEntry == glyph);

        SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData);

        // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
        if (svgGlyph.pathData.isEmpty()) {
            if (isVerticalText)
                currentPoint.move(0, advance);
            else
                currentPoint.move(advance, 0);
            continue;
         }

        context->save();

        if (isVerticalText) {
            glyphOrigin.setX(svgGlyph.verticalOriginX * scale);
            glyphOrigin.setY(svgGlyph.verticalOriginY * scale);
         }

        AffineTransform glyphPathTransform;
        glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
        glyphPathTransform.scale(scale, -scale);

        Path glyphPath = svgGlyph.pathData;
        glyphPath.transform(glyphPathTransform);

        if (activePaintingResource->applyResource(parentRenderObject, parentRenderObjectStyle, context, resourceMode)) {
            if (renderObject && renderObject->isSVGInlineText()) {
                const RenderSVGInlineText* textRenderer = toRenderSVGInlineText(renderObject);
                context->setStrokeThickness(context->strokeThickness() * textRenderer->scalingFactor());
            }
            activePaintingResource->postApplyResource(parentRenderObject, context, resourceMode, &glyphPath, 0);
         }
 
        context->restore();

        if (isVerticalText)
            currentPoint.move(0, advance);
        else
            currentPoint.move(advance, 0);
    }
}
Ejemplo n.º 22
0
GradientOpenVG* Gradient::platformGradient()
{
    if (m_gradient)
        return m_gradient;

    m_gradient = new GradientOpenVG;
    m_gradient->m_radial = m_radial;
    m_gradient->m_transformation = m_gradientSpaceTransformation;

    switch (m_spreadMethod) {
    case SpreadMethodPad:
        m_gradient->m_spread = VG_COLOR_RAMP_SPREAD_PAD;
        break;
    case SpreadMethodReflect:
        m_gradient->m_spread = VG_COLOR_RAMP_SPREAD_REFLECT;
        break;
    case SpreadMethodRepeat:
        m_gradient->m_spread = VG_COLOR_RAMP_SPREAD_REPEAT;
        break;
    }

    if (m_stops.size() > 0) {
        if (!m_stopsSorted) {
            std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
            m_stopsSorted = true;
        }
    }

    if (!m_radial) {
        // linear gradient
        m_gradient->m_coordinates.resize(4);
        m_gradient->m_coordinates[0] = m_p0.x();
        m_gradient->m_coordinates[1] = m_p0.y();
        m_gradient->m_coordinates[2] = m_p1.x();
        m_gradient->m_coordinates[3] = m_p1.y();

        if (!m_stops.isEmpty()) {
            m_gradient->m_colorStops.resize(m_stops.size()*5);
            for (int i = 0; i < m_stops.size(); i++) {
                m_gradient->m_colorStops[i*5] = m_stops[i].stop;
                m_gradient->m_colorStops[i*5 + 1] = m_stops[i].red;
                m_gradient->m_colorStops[i*5 + 2] = m_stops[i].green;
                m_gradient->m_colorStops[i*5 + 3] = m_stops[i].blue;
                m_gradient->m_colorStops[i*5 + 4] = m_stops[i].alpha;
            }
        }

        return m_gradient;
    }

    // radial gradient
    // OpenVG takes centre, focus, radius.  WebKit provides p0+r0, p1+r1.
    FloatPoint c0;
    FloatPoint c1;
    FloatPoint focus;
    double r0;
    double r1;

    bool reverseStops;
    // c0 should be the centre of the circle with the smaller radius r0
    if (m_r0 < m_r1) {
        c0 = m_p0;
        c1 = m_p1;
        r0 = m_r0;
        r1 = m_r1;
        reverseStops = false;
    } else {
        c0 = m_p1;
        c1 = m_p0;
        r0 = m_r1;
        r1 = m_r0;
        reverseStops = true;
    }

    if (r0 == r1) {
        if (c0 == c1)
            return m_gradient;

        m_gradient->m_coordinates.resize(5);
        m_gradient->m_coordinates[0] = c1.x();    // centre
        m_gradient->m_coordinates[1] = c1.y();
        m_gradient->m_coordinates[2] = c1.x();    // focal point
        m_gradient->m_coordinates[3] = c1.y();
        m_gradient->m_coordinates[4] = r1;      // radius of centre

        if (m_stops.size() < 1) {
            // if there's no stop, we should use transparent black
            m_gradient->m_colorStops.resize(5);
            m_gradient->m_colorStops[0] = 0;
            m_gradient->m_colorStops[1] = 0.0;
            m_gradient->m_colorStops[2] = 0.0;
            m_gradient->m_colorStops[3] = 0.0;
            m_gradient->m_colorStops[4] = 0.0;
        } else {
            int nStops = m_stops.size() > 1 ? 1 : 2;
            m_gradient->m_colorStops.resize(nStops * 5);

            m_gradient->m_colorStops[0] = 0;
            m_gradient->m_colorStops[1] = m_stops[0].red;
            m_gradient->m_colorStops[2] = m_stops[0].green;
            m_gradient->m_colorStops[3] = m_stops[0].blue;
            m_gradient->m_colorStops[4] = m_stops[0].alpha;
            if (nStops > 1) {
                m_gradient->m_colorStops[5] = 0;
                m_gradient->m_colorStops[6] = m_stops[nStops - 1].red;
                m_gradient->m_colorStops[7] = m_stops[nStops - 1].green;
                m_gradient->m_colorStops[8] = m_stops[nStops - 1].blue;
                m_gradient->m_colorStops[9] = m_stops[nStops - 1].alpha;
            }
        }

        return m_gradient;
    }

    double startOffset;
    bool emulateReflect = false;

    focus.setX((r1 * c0.x() - r0 * c1.x()) / (r1 - r0));
    focus.setY((r1 * c0.y() - r0 * c1.y()) / (r1 - r0));

    /* OpenVG doesn't support the inner circle and use instead a gradient focal.
     * That means we need to emulate the WebKit behaviour by processing the
     * WebKit gradient stops.
     * The SpreadMethodPad mode is quite easy to handle,
     * it's just a matter of stop position translation and calculation of
     * the corresponding OpenVG radial gradient focal.
     * The SpreadMethodReflect and SpreadMethodRepeat modes require a new
     * radial gradient, with a new outer circle equal to r1 - r0 in the SpreadMethodRepeat
     * case and 2 * (r1 - r0) in the SpreadMethodReflect case, and a new gradient stop
     * list that maps to the original WebKit stop list.
     */

    if ((m_spreadMethod == SpreadMethodReflect || m_spreadMethod == SpreadMethodRepeat) && r0 > 0.0) {
        double rOrig = r1;

        if (m_spreadMethod == SpreadMethodReflect) {
            r1 = 2 * r1 - r0;
            emulateReflect = true;
        }

        startOffset = fmod(r1, r1 - r0) / (r1 - r0) - 1.0;
        double r = r1 - r0;

        /* New position of outer circle. */
        double x = r * (c1.x() - focus.x()) / rOrig + focus.x();
        double y = r * (c1.y() - focus.y()) / rOrig + focus.y();

        c1.setX(x);
        c1.setY(y);
        r1 = r;
        r0 = 0.0;
    } else
        startOffset = r0 / r1;

    m_gradient->m_coordinates.resize(5);
    m_gradient->m_coordinates[0] = c1.x();       // centre
    m_gradient->m_coordinates[1] = c1.y();
    m_gradient->m_coordinates[2] = focus.x();    // focal point
    m_gradient->m_coordinates[3] = focus.y();
    m_gradient->m_coordinates[4] = r1;         // radius of centre

    if (emulateReflect)
        m_gradient->m_spread = VG_COLOR_RAMP_SPREAD_REPEAT;

    if (m_stops.size() < 1)
        return m_gradient;

    if (m_stops.size() == 1) {
        m_gradient->m_colorStops.resize(5);
        m_gradient->m_colorStops[0] = m_stops[0].stop;
        m_gradient->m_colorStops[1] = m_stops[0].red;
        m_gradient->m_colorStops[2] = m_stops[0].green;
        m_gradient->m_colorStops[3] = m_stops[0].blue;
        m_gradient->m_colorStops[4] = m_stops[0].alpha;
        return m_gradient;
    }

    int nStops;
    Vector<ColorStop> actualStops;
    if (emulateReflect || reverseStops) {
        nStops = emulateReflect ? m_stops.size() * 2 - 2: m_stops.size();
        actualStops.resize(nStops);

        for (int i = 0; i < nStops; i++) {
            if (reverseStops) {
                actualStops[i] = m_stops[nStops - i - 1];
                actualStops[i].stop = 1.0 - actualStops[i].stop;
            } else
                actualStops[i] = m_stops[i];

            if (emulateReflect) {
                actualStops[i].stop /= 2;
                if (i > 0 && i < (nStops - 1)) {
                    if (reverseStops) {
                        actualStops[i + nStops - 1] = m_stops[i];
                        actualStops[i + nStops - 1].stop = 0.5 + 0.5 * actualStops[i + nStops - 1].stop;
                    } else {
                        actualStops[i + nStops - 1] = m_stops[nStops - i - 1];
                        actualStops[i + nStops - 1].stop = 1 - 0.5 * actualStops[i + nStops - 1].stop;
                    }
                }
            }
        }
    } else {
        nStops = m_stops.size();
        actualStops = m_stops;
    }

    if (startOffset >= 0.0) {
        m_gradient->m_colorStops.resize(actualStops.size() * 5);
        for (int i = 0; i < nStops; i++) {
            double offset = startOffset + (1 - startOffset) * actualStops[i].stop;
            m_gradient->m_colorStops[i*5] = offset;
            m_gradient->m_colorStops[i*5 + 1] = actualStops[i].red;
            m_gradient->m_colorStops[i*5 + 2] = actualStops[i].green;
            m_gradient->m_colorStops[i*5 + 3] = actualStops[i].blue;
            m_gradient->m_colorStops[i*5 + 4] = actualStops[i].alpha;
        }

        return m_gradient;
    }

    bool found = FALSE;
    unsigned int offsetIndex;
    float startRed, startGreen, startBlue, startAlpha;
    float stopRed, stopGreen, stopBlue, stopAlpha;

    for (int i = 0; i < nStops; i++) {
        if (actualStops[i].stop >= -startOffset) {
            if (i > 0) {
                if (actualStops[i].stop != actualStops[i-1].stop) {
                    double x0, x1;

                    x0 = actualStops[i-1].stop;
                    x1 = actualStops[i].stop;
                    startRed = stopRed = actualStops[i-1].red + (actualStops[i].red - actualStops[i-1].red) * (-startOffset - x0) / (x1 - x0);
                    startGreen = stopGreen = actualStops[i-1].green + (actualStops[i].green - actualStops[i-1].green) * (-startOffset - x0) / (x1 - x0);
                    startBlue = stopBlue = actualStops[i-1].blue + (actualStops[i].blue - actualStops[i-1].blue) * (-startOffset - x0) / (x1 - x0);
                    startAlpha = stopAlpha = actualStops[i-1].alpha + (actualStops[i].alpha - actualStops[i-1].alpha) * (-startOffset - x0) / (x1 - x0);
                } else {
                    stopRed = actualStops[i-1].red;
                    stopGreen = actualStops[i-1].green;
                    stopBlue = actualStops[i-1].blue;
                    stopAlpha = actualStops[i-1].alpha;
                    startRed = actualStops[i].red;
                    startGreen = actualStops[i].green;
                    startBlue = actualStops[i].blue;
                    startAlpha = actualStops[i].alpha;
                }
            } else {
                startRed = stopRed = actualStops[i].red;
                startGreen = stopGreen = actualStops[i].green;
                startBlue = stopBlue = actualStops[i].blue;
                startAlpha = stopAlpha = actualStops[i].alpha;
            }
            offsetIndex = i;
            found = true;
            break;
        }
    }

    if (!found) {
        offsetIndex = nStops - 1;
        startRed = stopRed = actualStops[offsetIndex].red;
        startGreen = stopGreen = actualStops[offsetIndex].green;
        startBlue = stopBlue = actualStops[offsetIndex].blue;
        startAlpha = stopAlpha = actualStops[offsetIndex].alpha;
    }

    m_gradient->m_colorStops.resize((nStops + 2) * 5);
    int stopNum = 0;
    m_gradient->m_colorStops[stopNum * 5] = 0;
    m_gradient->m_colorStops[stopNum * 5 + 1] = startRed;
    m_gradient->m_colorStops[stopNum * 5 + 2] = startGreen;
    m_gradient->m_colorStops[stopNum * 5 + 3] = startBlue;
    m_gradient->m_colorStops[stopNum * 5 + 4] = startAlpha;
    ++stopNum;

    for (int i = offsetIndex; i < nStops; i++) {
        m_gradient->m_colorStops[stopNum * 5] = actualStops[i].stop + startOffset;
        m_gradient->m_colorStops[stopNum * 5 + 1] = actualStops[i].red;
        m_gradient->m_colorStops[stopNum * 5 + 2] = actualStops[i].green;
        m_gradient->m_colorStops[stopNum * 5 + 3] = actualStops[i].blue;
        m_gradient->m_colorStops[stopNum * 5 + 4] = actualStops[i].alpha;
        ++stopNum;
    }

    for (int i = 0; i < offsetIndex; i++) {
        m_gradient->m_colorStops[stopNum * 5] = 1.0 + actualStops[i].stop + startOffset;
        m_gradient->m_colorStops[stopNum * 5 + 1] = actualStops[i].red;
        m_gradient->m_colorStops[stopNum * 5 + 2] = actualStops[i].green;
        m_gradient->m_colorStops[stopNum * 5 + 3] = actualStops[i].blue;
        m_gradient->m_colorStops[stopNum * 5 + 4] = actualStops[i].alpha;
        ++stopNum;
    }

    m_gradient->m_colorStops[stopNum * 5] = 0;
    m_gradient->m_colorStops[stopNum * 5 + 1] = stopRed;
    m_gradient->m_colorStops[stopNum * 5 + 2] = stopGreen;
    m_gradient->m_colorStops[stopNum * 5 + 3] = stopBlue;
    m_gradient->m_colorStops[stopNum * 5 + 4] = stopAlpha;

    return m_gradient;
}
Ejemplo n.º 23
0
unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point)
{
    float tileWidth = paintingData.filterSize.width();
    ASSERT(tileWidth > 0);
    float tileHeight = paintingData.filterSize.height();
    ASSERT(tileHeight > 0);
    // Adjust the base frequencies if necessary for stitching.
    if (m_stitchTiles) {
        // When stitching tiled turbulence, the frequencies must be adjusted
        // so that the tile borders will be continuous.
        if (m_baseFrequencyX) {
            float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth;
            float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth;
            // BaseFrequency should be non-negative according to the standard.
            if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX)
                m_baseFrequencyX = lowFrequency;
            else
                m_baseFrequencyX = highFrequency;
        }
        if (m_baseFrequencyY) {
            float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight;
            float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight;
            if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY)
                m_baseFrequencyY = lowFrequency;
            else
                m_baseFrequencyY = highFrequency;
        }
        // Set up TurbulenceInitial stitch values.
        paintingData.width = roundf(tileWidth * m_baseFrequencyX);
        paintingData.wrapX = s_perlinNoise + paintingData.width;
        paintingData.height = roundf(tileHeight * m_baseFrequencyY);
        paintingData.wrapY = s_perlinNoise + paintingData.height;
    }
    float turbulenceFunctionResult = 0;
    FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY);
    float ratio = 1;
    for (int octave = 0; octave < m_numOctaves; ++octave) {
        if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
            turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio;
        else
            turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio;
        noiseVector.setX(noiseVector.x() * 2);
        noiseVector.setY(noiseVector.y() * 2);
        ratio *= 2;
        if (m_stitchTiles) {
            // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
            // adding it afterward simplifies to subtracting it once.
            paintingData.width *= 2;
            paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise;
            paintingData.height *= 2;
            paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise;
        }
    }

    // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise
    // and (turbulenceFunctionResult * 255) by turbulence.
    if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
        turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
    // Clamp result
    turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
    return static_cast<unsigned char>(turbulenceFunctionResult * 255);
}
Ejemplo n.º 24
0
void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 
                                const FloatPoint& point, int from, int to) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
        if (!fontElement)
            return;

        SVGTextRunWalkerDrawTextData data;
        FloatPoint currentPoint = point;
        float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);

        SVGPaintServer* activePaintServer = run.activePaintServer();

        // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
        if (!run.referencingRenderObject()) {
            ASSERT(!activePaintServer);

            // TODO: We're only supporting simple filled HTML text so far.
            SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
            solidPaintServer->setColor(context->fillColor());

            activePaintServer = solidPaintServer;
        }

        ASSERT(activePaintServer);

        int charsConsumed;
        String glyphName;
        bool isVerticalText = false;
        float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
        FloatPoint glyphOrigin;

        String language;

        // TODO: language matching & svg glyphs should be possible for HTML text, too.
        if (run.referencingRenderObject()) {
            isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());    

            if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
                language = element->getAttribute(XMLNames::langAttr);
        }

        if (!isVerticalText) {
            glyphOrigin.setX(fontData->horizontalOriginX() * scale);
            glyphOrigin.setY(fontData->horizontalOriginY() * scale);
        }

        data.extraCharsAvailable = 0;
        data.charsConsumed = 0;

        SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
        runWalker.walk(run, isVerticalText, language, from, to);

        SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;

        unsigned numGlyphs = data.glyphIdentifiers.size();
        unsigned fallbackCharacterIndex = 0;
        for (unsigned i = 0; i < numGlyphs; ++i) {
            const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
            if (identifier.isValid) {
                // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
                if (!identifier.pathData.isEmpty()) {
                    context->save();

                    if (isVerticalText) {
                        glyphOrigin.setX(identifier.verticalOriginX * scale);
                        glyphOrigin.setY(identifier.verticalOriginY * scale);
                    }

                    context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
                    context->scale(FloatSize(scale, -scale));

                    context->beginPath();
                    context->addPath(identifier.pathData);

                    if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
                        // Spec: Any properties specified on a text elements which represents a length, such as the
                        // 'stroke-width' property, might produce surprising results since the length value will be
                        // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
                        if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
                            context->setStrokeThickness(context->strokeThickness() / scale);

                        activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
                        activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
                    }

                    context->restore();
                }

                if (isVerticalText)
                    currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
                else
                    currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
            } else {
                // Handle system font fallback
                FontDescription fontDescription(context->font().fontDescription());
                fontDescription.setFamily(FontFamily());
                Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
                font.update(context->font().fontSelector());

                TextRun fallbackCharacterRun(run);
                fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
                font.drawText(context, fallbackCharacterRun, currentPoint);

                if (isVerticalText)
                    currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
                else
                    currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);

                fallbackCharacterIndex++;
            }
        }
    }
}