Example #1
0
void Path::transform(const AffineTransform& transformation)
{
    PlatformPathOpenVG* dst = new PlatformPathOpenVG();
    // dst->makeCompatibleContextCurrent() is called by the platform path
    // constructor, therefore not necessary to call it again here.
    PainterOpenVG::transformPath(dst->vgPath(), m_path->vgPath(), transformation);
    delete m_path;
    m_path = dst;

    m_path->m_currentPoint = transformation.mapPoint(m_path->m_currentPoint);
    m_path->m_subpathStartPoint = transformation.mapPoint(m_path->m_subpathStartPoint);
}
Example #2
0
static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
    // No GdkWindow to render to, so return true to fall back
    if (!i.context->gdkDrawable())
        return true;

    // Painting is disabled so just claim to have succeeded
    if (i.context->paintingDisabled())
        return false;

    GtkWidgetState mozState;
    setMozState(theme, &mozState, o);

    int flags;

    // We might want to make setting flags the caller's job at some point rather than doing it here.
    switch (type) {
        case MOZ_GTK_BUTTON:
            flags = GTK_RELIEF_NORMAL;
            break;
        case MOZ_GTK_CHECKBUTTON:
        case MOZ_GTK_RADIOBUTTON:
            flags = theme->isChecked(o);
            break;
        default:
            flags = 0;
            break;
    }

    AffineTransform ctm = i.context->getCTM();

    IntPoint pos = ctm.mapPoint(rect.location());
    GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height());
    GtkTextDirection direction = gtkTextDirection(o->style()->direction());

    // Find the clip rectangle
    cairo_t *cr = i.context->platformContext();
    double clipX1, clipX2, clipY1, clipY2;
    cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2);

    GdkRectangle gdkClipRect;
    gdkClipRect.width = clipX2 - clipX1;
    gdkClipRect.height = clipY2 - clipY1;
    IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1));
    gdkClipRect.x = clipPos.x();
    gdkClipRect.y = clipPos.y();

    gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);

    return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
}
WebMouseEvent WebEventFactory::createWebMouseEvent(const Evas_Event_Mouse_Down* event, const AffineTransform& toWebContent, const AffineTransform& toDeviceScreen)
{
    IntPoint pos(event->canvas.x, event->canvas.y);
    return WebMouseEvent(WebEvent::MouseDown,
        buttonForEvent(event->button),
        toWebContent.mapPoint(pos),
        toDeviceScreen.mapPoint(pos),
        0 /* deltaX */,
        0 /* deltaY */,
        0 /* deltaZ */,
        clickCountForEvent(event->flags),
        modifiersForEvent(event->modifiers),
        convertMillisecondToSecond(event->timestamp));
}
WebMouseEvent WebEventFactory::createWebMouseEvent(const Evas_Event_Mouse_Move* event, const AffineTransform& toWebContent, const AffineTransform& toDeviceScreen)
{
    IntPoint pos(event->cur.canvas.x, event->cur.canvas.y);
    return WebMouseEvent(WebEvent::MouseMove,
        buttonForEvent(event->buttons),
        toWebContent.mapPoint(pos),
        toDeviceScreen.mapPoint(pos),
        (event->cur.canvas.x - event->prev.canvas.x) /* deltaX */,
        (event->cur.canvas.y - event->prev.canvas.y) /* deltaY */,
        0 /* deltaZ */,
        0 /* clickCount */,
        modifiersForEvent(event->modifiers),
        convertMillisecondToSecond(event->timestamp));
}
Example #5
0
bool RenderThemeGtk::paintMozillaGtkWidget(GtkThemeWidgetType type, GraphicsContext* context, const IntRect& rect, GtkWidgetState* widgetState, int flags, GtkTextDirection textDirection)
{
    // Painting is disabled so just claim to have succeeded
    if (context->paintingDisabled())
        return false;

    PlatformRefPtr<GdkDrawable> drawable(context->gdkDrawable());
    GdkRectangle paintRect, clipRect;
    if (drawable) {
        AffineTransform ctm = context->getCTM();
        IntPoint pos = ctm.mapPoint(rect.location());
        paintRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height());

        // Intersect the cairo rectangle with the target widget region. This  will
        // prevent the theme drawing code from drawing into regions that cairo will
        // clip anyway.
        double clipX1, clipX2, clipY1, clipY2;
        cairo_clip_extents(context->platformContext(), &clipX1, &clipY1, &clipX2, &clipY2);
        IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1));

        clipRect.width = clipX2 - clipX1;
        clipRect.height = clipY2 - clipY1;
        clipRect.x = clipPos.x();
        clipRect.y = clipPos.y();
        gdk_rectangle_intersect(&paintRect, &clipRect, &clipRect);

    } else {
        // In some situations, like during print previews, this GraphicsContext is not
        // backed by a GdkDrawable. In those situations, we render onto a pixmap and then
        // copy the rendered data back to the GraphicsContext via Cairo.
        drawable = adoptPlatformRef(gdk_pixmap_new(0, rect.width(), rect.height(), gdk_visual_get_depth(gdk_visual_get_system())));
        paintRect = clipRect = IntRect(0, 0, rect.width(), rect.height());
    }

    moz_gtk_use_theme_parts(partsForDrawable(drawable.get()));
    bool success = moz_gtk_widget_paint(type, drawable.get(), &paintRect, &clipRect, widgetState, flags, textDirection) == MOZ_GTK_SUCCESS;

    // If the drawing was successful and we rendered onto a pixmap, copy the
    // results back to the original GraphicsContext.
    if (success && !context->gdkDrawable()) {
        cairo_t* cairoContext = context->platformContext();
        cairo_save(cairoContext);
        gdk_cairo_set_source_pixmap(cairoContext, drawable.get(), rect.x(), rect.y());
        cairo_paint(cairoContext);
        cairo_restore(cairoContext);
    }

    return !success;
}
WebTouchEvent WebEventFactory::createWebTouchEvent(Ewk_Touch_Event_Type type, const Eina_List* points, const Evas_Modifier* modifiers, const AffineTransform& toWebContent, const AffineTransform& toDeviceScreen, double timestamp)
{
    Vector<WebPlatformTouchPoint> touchPoints;
    touchPoints.reserveInitialCapacity(eina_list_count(points));

    const Eina_List* list;
    void* item;
    EINA_LIST_FOREACH(points, list, item) {
        Ewk_Touch_Point* point = static_cast<Ewk_Touch_Point*>(item);

        WebPlatformTouchPoint::TouchPointState state;
        switch (point->state) {
        case EVAS_TOUCH_POINT_UP:
            state = WebPlatformTouchPoint::TouchReleased;
            break;
        case EVAS_TOUCH_POINT_MOVE:
            state = WebPlatformTouchPoint::TouchMoved;
            break;
        case EVAS_TOUCH_POINT_DOWN:
            state = WebPlatformTouchPoint::TouchPressed;
            break;
        case EVAS_TOUCH_POINT_STILL:
            state = WebPlatformTouchPoint::TouchStationary;
            break;
        case EVAS_TOUCH_POINT_CANCEL:
            state = WebPlatformTouchPoint::TouchCancelled;
            break;
        default:
            ASSERT_NOT_REACHED();
            continue;
        }

        IntPoint pos(point->x, point->y);
        touchPoints.uncheckedAppend(WebPlatformTouchPoint(point->id, state, toDeviceScreen.mapPoint(pos), toWebContent.mapPoint(pos)));
    }
Example #7
0
FloatRect GraphicsContext::computeLineBoundsAndAntialiasingModeForText(const FloatPoint& point, float width, bool printing, bool& shouldAntialias, Color& color)
{
    FloatPoint origin = point;
    float thickness = std::max(strokeThickness(), 0.5f);

    shouldAntialias = true;
    if (!printing) {
        AffineTransform transform = getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
        if (transform.preservesAxisAlignment())
            shouldAntialias = false;

        // This code always draws a line that is at least one-pixel line high,
        // which tends to visually overwhelm text at small scales. To counter this
        // effect, an alpha is applied to the underline color when text is at small scales.

        // Just compute scale in x dimension, assuming x and y scales are equal.
        float scale = transform.b() ? sqrtf(transform.a() * transform.a() + transform.b() * transform.b()) : transform.a();
        if (scale < 1.0) {
            static const float minimumUnderlineAlpha = 0.4f;
            float shade = scale > minimumUnderlineAlpha ? scale : minimumUnderlineAlpha;
            int alpha = color.alpha() * shade;
            color = Color(color.red(), color.green(), color.blue(), alpha);
        }

        FloatPoint devicePoint = transform.mapPoint(point);
        FloatPoint deviceOrigin = FloatPoint(roundf(devicePoint.x()), ceilf(devicePoint.y()));
        if (auto inverse = transform.inverse())
            origin = inverse.value().mapPoint(deviceOrigin);
    }
    return FloatRect(origin.x(), origin.y(), width, thickness);
}
bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const
{
    EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData);

    int startPosition = data->position;
    int endPosition = startPosition + 1;
    if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
        return false;

    data->endPosition = FloatPoint(fragment.x, fragment.y);

    SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1);
    if (queryData->isVerticalText)
        data->endPosition.move(0, metrics.height());
    else
        data->endPosition.move(metrics.width(), 0);

    AffineTransform fragmentTransform;
    fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength);
    if (fragmentTransform.isIdentity())
        return true;

    data->endPosition = fragmentTransform.mapPoint(data->endPosition);
    return true;
}
Example #9
0
FloatRect GraphicsContext::computeLineBoundsAndAntialiasingModeForText(const FloatPoint& point, float width, bool printing, Color& color)
{
    FloatPoint origin = point;
    float thickness = std::max(strokeThickness(), 0.5f);
    if (printing)
        return FloatRect(origin, FloatSize(width, thickness));

    AffineTransform transform = getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
    // Just compute scale in x dimension, assuming x and y scales are equal.
    float scale = transform.b() ? sqrtf(transform.a() * transform.a() + transform.b() * transform.b()) : transform.a();
    if (scale < 1.0) {
        // This code always draws a line that is at least one-pixel line high,
        // which tends to visually overwhelm text at small scales. To counter this
        // effect, an alpha is applied to the underline color when text is at small scales.
        static const float minimumUnderlineAlpha = 0.4f;
        float shade = scale > minimumUnderlineAlpha ? scale : minimumUnderlineAlpha;
        int alpha = color.alpha() * shade;
        color = Color(color.red(), color.green(), color.blue(), alpha);
    }

    FloatPoint devicePoint = transform.mapPoint(point);
    // Visual overflow might occur here due to integral roundf/ceilf. visualOverflowForDecorations adjusts the overflow value for underline decoration.
    FloatPoint deviceOrigin = FloatPoint(roundf(devicePoint.x()), ceilf(devicePoint.y()));
    if (auto inverse = transform.inverse())
        origin = inverse.value().mapPoint(deviceOrigin);
    return FloatRect(origin, FloatSize(width, thickness));
}
std::pair<float, float> SVGGlyphToPathTranslator::extents()
{
    AffineTransform glyphPathTransform = transform();
    FloatPoint beginning = glyphPathTransform.mapPoint(m_currentPoint);
    FloatSize end = glyphPathTransform.mapSize(FloatSize(m_glyphBuffer.advanceAt(m_index)));
    return std::make_pair(beginning.x(), beginning.x() + end.width());
}
Example #11
0
static FloatPoint calculateGlyphPosition(const QueryData* queryData, const SVGTextFragment& fragment, int offsetInFragment)
{
    FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, offsetInFragment);
    if (fragment.isTransformed()) {
        AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength);
        glyphPosition = fragmentTransform.mapPoint(glyphPosition);
    }
    return glyphPosition;
}
Example #12
0
bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
{
    ASSERT(m_path);
    BoundingRectStrokeStyleApplier applier(this, style());

    if (hasNonScalingStroke()) {
        AffineTransform nonScalingTransform = nonScalingStrokeTransform();
        Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);

        return usePath->strokeContains(&applier, nonScalingTransform.mapPoint(point));
    }

    return m_path->strokeContains(&applier, point);
}
Example #13
0
bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
{
    ASSERT(m_path);
    StrokeData strokeData;
    SVGRenderSupport::applyStrokeStyleToStrokeData(&strokeData, style(), this);

    if (hasNonScalingStroke()) {
        AffineTransform nonScalingTransform = nonScalingStrokeTransform();
        Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);

        return usePath->strokeContains(nonScalingTransform.mapPoint(point), strokeData);
    }

    return m_path->strokeContains(point, strokeData);
}
WebTouchEvent WebEventFactory::createWebTouchEvent(const EwkTouchEvent* event, const AffineTransform& toWebContent)
{
    API::Array* touchPointsArray = toImpl(event->touchPoints());
    size_t size = touchPointsArray->size();

    Vector<WebPlatformTouchPoint> touchPoints;
    touchPoints.reserveInitialCapacity(size);

    for (size_t i = 0; i < size; ++i) {
        if (EwkTouchPoint* point = touchPointsArray->at<EwkTouchPoint>(i))
            touchPoints.uncheckedAppend(WebPlatformTouchPoint(point->id(), toWebPlatformTouchPointState(point->state()), toIntPoint(point->screenPosition()), toWebContent.mapPoint(toIntPoint(point->position())), toIntSize(point->radius()), point->rotationAngle(), point->forceFactor()));
    }

    return WebTouchEvent(toWebEventType(event->eventType()), touchPoints, toWebEventModifiers(event->modifiers()), event->timestamp());
}
Example #15
0
// This works by converting the SVG arc to "simple" beziers.
// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
// See also SVG implementation notes:
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
bool SVGPathNormalizer::decomposeArcToCubic(const FloatPoint& currentPoint,
                                            const PathSegmentData& arcSegment) {
  // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a
  // "lineto") joining the endpoints.
  // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
  float rx = fabsf(arcSegment.arcRadii().x());
  float ry = fabsf(arcSegment.arcRadii().y());
  if (!rx || !ry)
    return false;

  // If the current point and target point for the arc are identical, it should
  // be treated as a zero length path. This ensures continuity in animations.
  if (arcSegment.targetPoint == currentPoint)
    return false;

  float angle = arcSegment.arcAngle();

  FloatSize midPointDistance = currentPoint - arcSegment.targetPoint;
  midPointDistance.scale(0.5f);

  AffineTransform pointTransform;
  pointTransform.rotate(-angle);

  FloatPoint transformedMidPoint = pointTransform.mapPoint(
      FloatPoint(midPointDistance.width(), midPointDistance.height()));
  float squareRx = rx * rx;
  float squareRy = ry * ry;
  float squareX = transformedMidPoint.x() * transformedMidPoint.x();
  float squareY = transformedMidPoint.y() * transformedMidPoint.y();

  // Check if the radii are big enough to draw the arc, scale radii if not.
  // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
  float radiiScale = squareX / squareRx + squareY / squareRy;
  if (radiiScale > 1) {
    rx *= sqrtf(radiiScale);
    ry *= sqrtf(radiiScale);
  }

  pointTransform.makeIdentity();
  pointTransform.scale(1 / rx, 1 / ry);
  pointTransform.rotate(-angle);

  FloatPoint point1 = pointTransform.mapPoint(currentPoint);
  FloatPoint point2 = pointTransform.mapPoint(arcSegment.targetPoint);
  FloatSize delta = point2 - point1;

  float d = delta.width() * delta.width() + delta.height() * delta.height();
  float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f);

  float scaleFactor = sqrtf(scaleFactorSquared);
  if (arcSegment.arcSweep == arcSegment.arcLarge)
    scaleFactor = -scaleFactor;

  delta.scale(scaleFactor);
  FloatPoint centerPoint = point1 + point2;
  centerPoint.scale(0.5f, 0.5f);
  centerPoint.move(-delta.height(), delta.width());

  float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians();
  float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians();

  float thetaArc = theta2 - theta1;
  if (thetaArc < 0 && arcSegment.arcSweep)
    thetaArc += twoPiFloat;
  else if (thetaArc > 0 && !arcSegment.arcSweep)
    thetaArc -= twoPiFloat;

  pointTransform.makeIdentity();
  pointTransform.rotate(angle);
  pointTransform.scale(rx, ry);

  // Some results of atan2 on some platform implementations are not exact
  // enough. So that we get more cubic curves than expected here. Adding 0.001f
  // reduces the count of sgements to the correct count.
  int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f)));
  for (int i = 0; i < segments; ++i) {
    float startTheta = theta1 + i * thetaArc / segments;
    float endTheta = theta1 + (i + 1) * thetaArc / segments;

    float t = (8 / 6.f) * tanf(0.25f * (endTheta - startTheta));
    if (!std::isfinite(t))
      return false;
    float sinStartTheta = sinf(startTheta);
    float cosStartTheta = cosf(startTheta);
    float sinEndTheta = sinf(endTheta);
    float cosEndTheta = cosf(endTheta);

    point1 = FloatPoint(cosStartTheta - t * sinStartTheta,
                        sinStartTheta + t * cosStartTheta);
    point1.move(centerPoint.x(), centerPoint.y());
    FloatPoint targetPoint = FloatPoint(cosEndTheta, sinEndTheta);
    targetPoint.move(centerPoint.x(), centerPoint.y());
    point2 = targetPoint;
    point2.move(t * sinEndTheta, -t * cosEndTheta);

    PathSegmentData cubicSegment;
    cubicSegment.command = PathSegCurveToCubicAbs;
    cubicSegment.point1 = pointTransform.mapPoint(point1);
    cubicSegment.point2 = pointTransform.mapPoint(point2);
    cubicSegment.targetPoint = pointTransform.mapPoint(targetPoint);

    m_consumer->emitSegment(cubicSegment);
  }
  return true;
}
Example #16
0
// This works by converting the SVG arc to "simple" beziers.
// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
// See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
bool SVGPathParser::decomposeArcToCubic(float angle, float rx, float ry, FloatPoint& point1, FloatPoint& point2, bool largeArcFlag, bool sweepFlag)
{
    FloatSize midPointDistance = point1 - point2;
    midPointDistance.scale(0.5f);

    AffineTransform pointTransform;
    pointTransform.rotate(-angle);

    FloatPoint transformedMidPoint = pointTransform.mapPoint(FloatPoint(midPointDistance.width(), midPointDistance.height()));
    float squareRx = rx * rx;
    float squareRy = ry * ry;
    float squareX = transformedMidPoint.x() * transformedMidPoint.x();
    float squareY = transformedMidPoint.y() * transformedMidPoint.y();

    // Check if the radii are big enough to draw the arc, scale radii if not.
    // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
    float radiiScale = squareX / squareRx + squareY / squareRy;
    if (radiiScale > 1) {
        rx *= sqrtf(radiiScale);
        ry *= sqrtf(radiiScale);
    }

    pointTransform.makeIdentity();
    pointTransform.scale(1 / rx, 1 / ry);
    pointTransform.rotate(-angle);

    point1 = pointTransform.mapPoint(point1);
    point2 = pointTransform.mapPoint(point2);
    FloatSize delta = point2 - point1;

    float d = delta.width() * delta.width() + delta.height() * delta.height();
    float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f);

    float scaleFactor = sqrtf(scaleFactorSquared);
    if (sweepFlag == largeArcFlag)
        scaleFactor = -scaleFactor;

    delta.scale(scaleFactor);
    FloatPoint centerPoint = point1 + point2;
    centerPoint.scale(0.5f);
    centerPoint.move(-delta.height(), delta.width());

    float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians();
    float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians();

    float thetaArc = theta2 - theta1;
    if (thetaArc < 0 && sweepFlag)
        thetaArc += 2 * piFloat;
    else if (thetaArc > 0 && !sweepFlag)
        thetaArc -= 2 * piFloat;

    pointTransform.makeIdentity();
    pointTransform.rotate(angle);
    pointTransform.scale(rx, ry);

    // Some results of atan2 on some platform implementations are not exact enough. So that we get more
    // cubic curves than expected here. Adding 0.001f reduces the count of sgements to the correct count.
    int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f)));
    for (int i = 0; i < segments; ++i) {
        float startTheta = theta1 + i * thetaArc / segments;
        float endTheta = theta1 + (i + 1) * thetaArc / segments;

        float t = (8 / 6.f) * tanf(0.25f * (endTheta - startTheta));
        if (!std::isfinite(t))
            return false;
        float sinStartTheta = sinf(startTheta);
        float cosStartTheta = cosf(startTheta);
        float sinEndTheta = sinf(endTheta);
        float cosEndTheta = cosf(endTheta);

        point1 = FloatPoint(cosStartTheta - t * sinStartTheta, sinStartTheta + t * cosStartTheta);
        point1.move(centerPoint.x(), centerPoint.y());
        FloatPoint targetPoint = FloatPoint(cosEndTheta, sinEndTheta);
        targetPoint.move(centerPoint.x(), centerPoint.y());
        point2 = targetPoint;
        point2.move(t * sinEndTheta, -t * cosEndTheta);

        m_consumer.curveToCubic(pointTransform.mapPoint(point1), pointTransform.mapPoint(point2),
                                 pointTransform.mapPoint(targetPoint), AbsoluteCoordinates);
    }
    return true;
}
Example #17
0
std::pair<float, float> CairoGlyphToPathTranslator::extents()
{
    FloatPoint beginning = m_translation.mapPoint(FloatPoint());
    FloatSize end = m_translation.mapSize(m_glyphBuffer.advanceAt(m_index));
    return std::make_pair(static_cast<float>(beginning.x()), static_cast<float>(beginning.x() + end.width()));
}
Example #18
0
static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
    GRefPtr<GdkDrawable> pixmap;

    // Painting is disabled so just claim to have succeeded
    if (i.context->paintingDisabled())
        return false;

    // No GdkWindow to render to, so return true to fall back
    if (!i.context->gdkDrawable())
        // This is slow, used only during printing process
        pixmap = adoptGRef(gdk_pixmap_new(0, rect.width(), rect.height(), gdk_visual_get_system()->depth));

    GtkWidgetState mozState;
    setMozillaState(theme, &mozState, o);

    int flags;

    // We might want to make setting flags the caller's job at some point rather than doing it here.
    switch (type) {
    case MOZ_GTK_BUTTON:
        flags = GTK_RELIEF_NORMAL;
        break;
    case MOZ_GTK_CHECKBUTTON:
    case MOZ_GTK_RADIOBUTTON:
        flags = theme->isChecked(o);
        break;
    default:
        flags = 0;
        break;
    }

    GtkTextDirection direction = gtkTextDirection(o->style()->direction());

    if (pixmap) {
        GdkRectangle gdkRect = IntRect(0, 0, rect.width(), rect.height());

        moz_gtk_use_theme_parts(theme->partsForDrawable(pixmap.get()));

        bool result = moz_gtk_widget_paint(type, pixmap.get(), &gdkRect, &gdkRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;

        if (!result) {
            cairo_t* cr = i.context->platformContext();
            gdk_cairo_set_source_pixmap(cr, pixmap.get(), rect.x(), rect.y());
            cairo_paint(cr);
        }

        return result;
    }

    AffineTransform ctm = i.context->getCTM();

    IntPoint pos = ctm.mapPoint(rect.location());
    GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height());

    // Find the clip rectangle
    cairo_t* cr = i.context->platformContext();
    double clipX1, clipX2, clipY1, clipY2;
    cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2);

    GdkRectangle gdkClipRect;
    gdkClipRect.width = clipX2 - clipX1;
    gdkClipRect.height = clipY2 - clipY1;
    IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1));
    gdkClipRect.x = clipPos.x();
    gdkClipRect.y = clipPos.y();

    gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);

    // Since the theme renderer is going to be drawing onto this GdkDrawable,
    // select the appropriate widgets for the drawable depth.
    moz_gtk_use_theme_parts(theme->partsForDrawable(i.context->gdkDrawable()));
    return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
}