зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1168527 - Replay clips into the system cairo on GTK3. r=lsalzman
--HG-- extra : rebase_source : 013e1811f6b3fa1f599531153c292d7a5136f087 extra : histedit_source : 7c3f596514ea87840a0bd231b247b119ed9d3048
This commit is contained in:
Родитель
198ba930fe
Коммит
40b78be093
|
@ -35,6 +35,7 @@
|
|||
#include "gfxGdkNativeRenderer.h"
|
||||
#include "mozilla/gfx/BorrowedContext.h"
|
||||
#include "mozilla/gfx/HelpersCairo.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
# ifdef CAIRO_HAS_XLIB_SURFACE
|
||||
|
@ -715,6 +716,85 @@ ThemeRenderer::DrawWithGDK(GdkDrawable * drawable, gint offsetX,
|
|||
return NS_OK;
|
||||
}
|
||||
#else
|
||||
class SystemCairoClipper : public ClipExporter {
|
||||
public:
|
||||
SystemCairoClipper(cairo_t* aContext) : mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BeginClip(const Matrix& aTransform) override
|
||||
{
|
||||
cairo_matrix_t mat;
|
||||
GfxMatrixToCairoMatrix(aTransform, mat);
|
||||
cairo_set_matrix(mContext, &mat);
|
||||
|
||||
cairo_new_path(mContext);
|
||||
}
|
||||
|
||||
void
|
||||
MoveTo(const Point &aPoint) override
|
||||
{
|
||||
cairo_move_to(mContext, aPoint.x, aPoint.y);
|
||||
mCurrentPoint = aPoint;
|
||||
}
|
||||
|
||||
void
|
||||
LineTo(const Point &aPoint) override
|
||||
{
|
||||
cairo_line_to(mContext, aPoint.x, aPoint.y);
|
||||
mCurrentPoint = aPoint;
|
||||
}
|
||||
|
||||
void
|
||||
BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3) override
|
||||
{
|
||||
cairo_curve_to(mContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y);
|
||||
mCurrentPoint = aCP3;
|
||||
}
|
||||
|
||||
void
|
||||
QuadraticBezierTo(const Point &aCP1, const Point &aCP2) override
|
||||
{
|
||||
Point CP0 = CurrentPoint();
|
||||
Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
|
||||
Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
|
||||
Point CP3 = aCP2;
|
||||
cairo_curve_to(mContext, CP1.x, CP1.y, CP2.x, CP2.y, CP3.x, CP3.y);
|
||||
mCurrentPoint = aCP2;
|
||||
}
|
||||
|
||||
void
|
||||
Arc(const Point &aOrigin, float aRadius, float aStartAngle, float aEndAngle,
|
||||
bool aAntiClockwise) override
|
||||
{
|
||||
ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle,
|
||||
aAntiClockwise);
|
||||
}
|
||||
|
||||
void
|
||||
Close() override
|
||||
{
|
||||
cairo_close_path(mContext);
|
||||
}
|
||||
|
||||
void
|
||||
EndClip() override
|
||||
{
|
||||
cairo_clip(mContext);
|
||||
}
|
||||
|
||||
Point
|
||||
CurrentPoint() const override
|
||||
{
|
||||
return mCurrentPoint;
|
||||
}
|
||||
|
||||
private:
|
||||
cairo_t* mContext;
|
||||
Point mCurrentPoint;
|
||||
};
|
||||
|
||||
static void
|
||||
DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
||||
GtkWidgetState aState, GtkThemeWidgetType aGTKWidgetType,
|
||||
|
@ -722,19 +802,29 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
|||
bool aSnapped, const Point& aDrawOrigin, const nsIntSize& aDrawSize,
|
||||
GdkRectangle& aGDKRect, nsITheme::Transparency aTransparency)
|
||||
{
|
||||
Point drawOffset;
|
||||
Matrix transform;
|
||||
if (!aSnapped) {
|
||||
// If we are not snapped, we depend on the DT for translation.
|
||||
drawOffset = aDrawOrigin;
|
||||
transform = aDrawTarget->GetTransform().PreTranslate(aDrawOrigin);
|
||||
} else {
|
||||
// Otherwise, we only need to take the device offset into account.
|
||||
drawOffset = aDrawOrigin - aContext->GetDeviceOffset();
|
||||
transform = Matrix::Translation(drawOffset);
|
||||
}
|
||||
|
||||
if (aScaleFactor != 1)
|
||||
transform.PreScale(aScaleFactor, aScaleFactor);
|
||||
|
||||
cairo_matrix_t mat;
|
||||
GfxMatrixToCairoMatrix(transform, mat);
|
||||
|
||||
#ifndef MOZ_TREE_CAIRO
|
||||
// Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
|
||||
BorrowedCairoContext borrow(aDrawTarget);
|
||||
if (borrow.mCairo) {
|
||||
if (aSnapped) {
|
||||
cairo_identity_matrix(borrow.mCairo);
|
||||
}
|
||||
if (aDrawOrigin != Point(0, 0)) {
|
||||
cairo_translate(borrow.mCairo, aDrawOrigin.x, aDrawOrigin.y);
|
||||
}
|
||||
if (aScaleFactor != 1) {
|
||||
cairo_scale(borrow.mCairo, aScaleFactor, aScaleFactor);
|
||||
}
|
||||
cairo_set_matrix(borrow.mCairo, &mat);
|
||||
|
||||
moz_gtk_widget_paint(aGTKWidgetType, borrow.mCairo, &aGDKRect, &aState, aFlags, aDirection);
|
||||
|
||||
|
@ -744,40 +834,33 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
|||
#endif
|
||||
|
||||
// A direct Cairo draw target is not available, so we need to create a temporary one.
|
||||
bool needClip = !aSnapped || aContext->HasComplexClip();
|
||||
#if defined(MOZ_X11) && defined(CAIRO_HAS_XLIB_SURFACE)
|
||||
if (!needClip) {
|
||||
// If using a Cairo xlib surface, then try to reuse it.
|
||||
BorrowedXlibDrawable borrow(aDrawTarget);
|
||||
if (borrow.GetDrawable()) {
|
||||
nsIntSize size = aDrawTarget->GetSize();
|
||||
cairo_surface_t* surf = nullptr;
|
||||
// Check if the surface is using XRender.
|
||||
// If using a Cairo xlib surface, then try to reuse it.
|
||||
BorrowedXlibDrawable borrow(aDrawTarget);
|
||||
if (borrow.GetDrawable()) {
|
||||
nsIntSize size = aDrawTarget->GetSize();
|
||||
cairo_surface_t* surf = nullptr;
|
||||
// Check if the surface is using XRender.
|
||||
#ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
|
||||
if (borrow.GetXRenderFormat()) {
|
||||
surf = cairo_xlib_surface_create_with_xrender_format(
|
||||
if (borrow.GetXRenderFormat()) {
|
||||
surf = cairo_xlib_surface_create_with_xrender_format(
|
||||
borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetScreen(),
|
||||
borrow.GetXRenderFormat(), size.width, size.height);
|
||||
} else {
|
||||
} else {
|
||||
#else
|
||||
if (! borrow.GetXRenderFormat()) {
|
||||
#endif
|
||||
surf = cairo_xlib_surface_create(
|
||||
borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetVisual(),
|
||||
size.width, size.height);
|
||||
borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetVisual(),
|
||||
size.width, size.height);
|
||||
}
|
||||
if (!NS_WARN_IF(!surf)) {
|
||||
cairo_t* cr = cairo_create(surf);
|
||||
if (!NS_WARN_IF(!cr)) {
|
||||
cairo_new_path(cr);
|
||||
cairo_rectangle(cr, aDrawOrigin.x, aDrawOrigin.y, aDrawSize.width, aDrawSize.height);
|
||||
cairo_clip(cr);
|
||||
if (aDrawOrigin != Point(0, 0)) {
|
||||
cairo_translate(cr, aDrawOrigin.x, aDrawOrigin.y);
|
||||
}
|
||||
if (aScaleFactor != 1) {
|
||||
cairo_scale(cr, aScaleFactor, aScaleFactor);
|
||||
}
|
||||
RefPtr<SystemCairoClipper> clipper = new SystemCairoClipper(cr);
|
||||
aContext->ExportClip(*clipper);
|
||||
|
||||
cairo_set_matrix(cr, &mat);
|
||||
|
||||
moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
|
||||
|
||||
|
@ -788,7 +871,6 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
|||
borrow.Finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if the widget requires complex masking that must be composited.
|
||||
|
@ -797,18 +879,18 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
|||
nsIntSize size;
|
||||
int32_t stride;
|
||||
SurfaceFormat format;
|
||||
if (!needClip && aDrawTarget->LockBits(&data, &size, &stride, &format)) {
|
||||
if (aDrawTarget->LockBits(&data, &size, &stride, &format)) {
|
||||
// Create a Cairo image surface context the device rectangle.
|
||||
cairo_surface_t* surf =
|
||||
cairo_image_surface_create_for_data(
|
||||
data + int32_t(aDrawOrigin.y) * stride + int32_t(aDrawOrigin.x) * BytesPerPixel(format),
|
||||
GfxFormatToCairoFormat(format), aDrawSize.width, aDrawSize.height, stride);
|
||||
data, GfxFormatToCairoFormat(format), size.width, size.height, stride);
|
||||
if (!NS_WARN_IF(!surf)) {
|
||||
cairo_t* cr = cairo_create(surf);
|
||||
if (!NS_WARN_IF(!cr)) {
|
||||
if (aScaleFactor != 1) {
|
||||
cairo_scale(cr, aScaleFactor, aScaleFactor);
|
||||
}
|
||||
RefPtr<SystemCairoClipper> clipper = new SystemCairoClipper(cr);
|
||||
aContext->ExportClip(*clipper);
|
||||
|
||||
cairo_set_matrix(cr, &mat);
|
||||
|
||||
moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
|
||||
|
||||
|
@ -845,17 +927,17 @@ DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
|
|||
dataSurface->Unmap();
|
||||
|
||||
if (cr) {
|
||||
if (needClip || aTransparency != nsITheme::eOpaque) {
|
||||
if (!aSnapped || aTransparency != nsITheme::eOpaque) {
|
||||
// The widget either needs to be masked or has transparency, so use the slower drawing path.
|
||||
aDrawTarget->DrawSurface(dataSurface,
|
||||
Rect(aSnapped ? aDrawOrigin - aDrawTarget->GetTransform().GetTranslation() : aDrawOrigin,
|
||||
Rect(aSnapped ? drawOffset - aDrawTarget->GetTransform().GetTranslation() : drawOffset,
|
||||
Size(aDrawSize)),
|
||||
Rect(0, 0, aDrawSize.width, aDrawSize.height));
|
||||
} else {
|
||||
// The widget is a simple opaque rectangle, so just copy it out.
|
||||
aDrawTarget->CopySurface(dataSurface,
|
||||
IntRect(0, 0, aDrawSize.width, aDrawSize.height),
|
||||
TruncatedToInt(aDrawOrigin));
|
||||
TruncatedToInt(drawOffset));
|
||||
}
|
||||
|
||||
cairo_destroy(cr);
|
||||
|
|
Загрузка…
Ссылка в новой задаче