зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1728107 - Remove gfxXlibNativeRenderer and gfxGdkNativeRenderer. r=jrmuizel
This code is no longer used by anything. Differential Revision: https://phabricator.services.mozilla.com/D123944
This commit is contained in:
Родитель
06c451e911
Коммит
8dfbdef80e
|
@ -1,15 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxGdkNativeRenderer.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatformGtk.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
# include <gdk/gdkx.h>
|
||||
# include "cairo-xlib.h"
|
||||
# include "gfxXlibSurface.h"
|
||||
|
||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFXGDKNATIVERENDER_H_
|
||||
#define GFXGDKNATIVERENDER_H_
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include "nsSize.h"
|
||||
#ifdef MOZ_X11
|
||||
# include "gfxXlibNativeRenderer.h"
|
||||
#endif
|
||||
|
||||
class gfxContext;
|
||||
|
||||
/**
|
||||
* This class lets us take code that draws into an GDK drawable and lets us
|
||||
* use it to draw into any Thebes context. The user should subclass this class,
|
||||
* override DrawWithGDK, and then call Draw(). The drawing will be subjected
|
||||
* to all Thebes transformations, clipping etc.
|
||||
*/
|
||||
class gfxGdkNativeRenderer
|
||||
#ifdef MOZ_X11
|
||||
: private gfxXlibNativeRenderer
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Perform the native drawing.
|
||||
* @param offsetX draw at this offset into the given drawable
|
||||
* @param offsetY draw at this offset into the given drawable
|
||||
* @param clipRects an array of rects; clip to the union
|
||||
* @param numClipRects the number of rects in the array, or zero if
|
||||
* no clipping is required
|
||||
*/
|
||||
|
||||
enum {
|
||||
// If set, then Draw() is opaque, i.e., every pixel in the intersection
|
||||
// of the clipRect and (offset.x,offset.y,bounds.width,bounds.height)
|
||||
// will be set and there is no dependence on what the existing pixels
|
||||
// in the drawable are set to.
|
||||
DRAW_IS_OPAQUE =
|
||||
#ifdef MOZ_X11
|
||||
gfxXlibNativeRenderer::DRAW_IS_OPAQUE
|
||||
#else
|
||||
0x1
|
||||
#endif
|
||||
// If set, then numClipRects can be zero or one.
|
||||
// If not set, then numClipRects will be zero.
|
||||
,
|
||||
DRAW_SUPPORTS_CLIP_RECT =
|
||||
#ifdef MOZ_X11
|
||||
gfxXlibNativeRenderer::DRAW_SUPPORTS_CLIP_RECT
|
||||
#else
|
||||
0x2
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flags see above
|
||||
* @param bounds Draw()'s drawing is guaranteed to be restricted to
|
||||
* the rectangle (offset.x,offset.y,bounds.width,bounds.height)
|
||||
* @param dpy a display to use for the drawing if ctx doesn't have one
|
||||
*/
|
||||
|
||||
private:
|
||||
#ifdef MOZ_X11
|
||||
// for gfxXlibNativeRenderer:
|
||||
virtual nsresult DrawWithXlib(cairo_surface_t* surface, nsIntPoint offset,
|
||||
mozilla::gfx::IntRect* clipRects,
|
||||
uint32_t numClipRects) override;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /*GFXGDKNATIVERENDER_H_*/
|
|
@ -1,588 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxXlibNativeRenderer.h"
|
||||
|
||||
#include "gfxXlibSurface.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxAlphaRecovery.h"
|
||||
#include "cairo-xlib.h"
|
||||
#include "cairo-xlib-xrender.h"
|
||||
#include "mozilla/gfx/BorrowedContext.h"
|
||||
#include "mozilla/gfx/HelpersCairo.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
#if 0
|
||||
# include <stdio.h>
|
||||
# define NATIVE_DRAWING_NOTE(m) fprintf(stderr, m)
|
||||
#else
|
||||
# define NATIVE_DRAWING_NOTE(m) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* We have four basic strategies available:
|
||||
|
||||
1) 'direct': If the target is an xlib surface, and other conditions are met,
|
||||
we can pass the underlying drawable directly to the callback.
|
||||
|
||||
2) 'simple': If the drawing is opaque, or we can draw to a surface with an
|
||||
alpha channel, then we can create a temporary xlib surface, pass its
|
||||
underlying drawable to the callback, and composite the result using
|
||||
cairo.
|
||||
|
||||
3) 'copy-background': If the drawing is not opaque but the target is
|
||||
opaque, and we can draw to a surface with format such that pixel
|
||||
conversion to and from the target format is exact, we can create a
|
||||
temporary xlib surface, copy the background from the target, pass the
|
||||
underlying drawable to the callback, and copy back to the target.
|
||||
|
||||
This strategy is not used if the pixel format conversion is not exact,
|
||||
because that would mean that drawing intended to be very transparent
|
||||
messes with other content.
|
||||
|
||||
The strategy is prefered over simple for non-opaque drawing and opaque
|
||||
targets on the same screen as compositing without alpha is a simpler
|
||||
operation.
|
||||
|
||||
4) 'alpha-extraction': create a temporary xlib surface, fill with black,
|
||||
pass its underlying drawable to the callback, copy the results to a
|
||||
cairo image surface, repeat with a white background, update the on-black
|
||||
image alpha values by comparing the two images, then paint the on-black
|
||||
image using cairo.
|
||||
|
||||
Sure would be nice to have an X extension or GL to do this for us on the
|
||||
server...
|
||||
*/
|
||||
|
||||
static cairo_bool_t _convert_coord_to_int(double coord, int32_t* v) {
|
||||
*v = (int32_t)coord;
|
||||
/* XXX allow some tolerance here? */
|
||||
return *v == coord;
|
||||
}
|
||||
|
||||
static bool _get_rectangular_clip(cairo_t* cr, const IntRect& bounds,
|
||||
bool* need_clip, IntRect* rectangles,
|
||||
int max_rectangles, int* num_rectangles) {
|
||||
cairo_rectangle_list_t* cliplist;
|
||||
cairo_rectangle_t* clips;
|
||||
int i;
|
||||
bool retval = true;
|
||||
|
||||
cliplist = cairo_copy_clip_rectangle_list(cr);
|
||||
if (cliplist->status != CAIRO_STATUS_SUCCESS) {
|
||||
retval = false;
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: non-rectangular clip");
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
/* the clip is always in surface backend coordinates (i.e. native backend
|
||||
* coords) */
|
||||
clips = cliplist->rectangles;
|
||||
|
||||
for (i = 0; i < cliplist->num_rectangles; ++i) {
|
||||
IntRect rect;
|
||||
if (!_convert_coord_to_int(clips[i].x, &rect.x) ||
|
||||
!_convert_coord_to_int(clips[i].y, &rect.y) ||
|
||||
!_convert_coord_to_int(clips[i].width, &rect.width) ||
|
||||
!_convert_coord_to_int(clips[i].height, &rect.height)) {
|
||||
retval = false;
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: non-integer clip");
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
if (rect.IsEqualInterior(bounds)) {
|
||||
/* the bounds are entirely inside the clip region so we don't need to
|
||||
* clip. */
|
||||
*need_clip = false;
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
NS_ASSERTION(bounds.Contains(rect),
|
||||
"Was expecting to be clipped to bounds");
|
||||
|
||||
if (i >= max_rectangles) {
|
||||
retval = false;
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: unsupported clip rectangle count");
|
||||
goto FINISH;
|
||||
}
|
||||
|
||||
rectangles[i] = rect;
|
||||
}
|
||||
|
||||
*need_clip = true;
|
||||
*num_rectangles = cliplist->num_rectangles;
|
||||
|
||||
FINISH:
|
||||
cairo_rectangle_list_destroy(cliplist);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define MAX_STATIC_CLIP_RECTANGLES 50
|
||||
|
||||
/**
|
||||
* Try the direct path.
|
||||
* @return True if we took the direct path
|
||||
*/
|
||||
bool gfxXlibNativeRenderer::DrawDirect(DrawTarget* aDT, IntSize size,
|
||||
uint32_t flags, Screen* screen,
|
||||
Visual* visual) {
|
||||
// We need to actually borrow the context because we want to read out the
|
||||
// clip rectangles.
|
||||
BorrowedCairoContext borrowed(aDT);
|
||||
if (!borrowed.mCairo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool direct = DrawCairo(borrowed.mCairo, size, flags, screen, visual);
|
||||
borrowed.Finish();
|
||||
|
||||
return direct;
|
||||
}
|
||||
|
||||
bool gfxXlibNativeRenderer::DrawCairo(cairo_t* cr, IntSize size, uint32_t flags,
|
||||
Screen* screen, Visual* visual) {
|
||||
/* Check that the target surface is an xlib surface. */
|
||||
cairo_surface_t* target = cairo_get_group_target(cr);
|
||||
if (cairo_surface_get_type(target) != CAIRO_SURFACE_TYPE_XLIB) {
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: non-X surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
cairo_matrix_t matrix;
|
||||
cairo_get_matrix(cr, &matrix);
|
||||
double device_offset_x, device_offset_y;
|
||||
cairo_surface_get_device_offset(target, &device_offset_x, &device_offset_y);
|
||||
|
||||
/* Draw() checked that the matrix contained only a very-close-to-integer
|
||||
translation. Here (and in several other places and thebes) device
|
||||
offsets are assumed to be integer. */
|
||||
NS_ASSERTION(int32_t(device_offset_x) == device_offset_x &&
|
||||
int32_t(device_offset_y) == device_offset_y,
|
||||
"Expected integer device offsets");
|
||||
IntPoint offset(NS_lroundf(matrix.x0 + device_offset_x),
|
||||
NS_lroundf(matrix.y0 + device_offset_y));
|
||||
|
||||
int max_rectangles = 0;
|
||||
if (flags & DRAW_SUPPORTS_CLIP_RECT) {
|
||||
max_rectangles = 1;
|
||||
}
|
||||
if (flags & DRAW_SUPPORTS_CLIP_LIST) {
|
||||
max_rectangles = MAX_STATIC_CLIP_RECTANGLES;
|
||||
}
|
||||
|
||||
/* The client won't draw outside the surface so consider this when
|
||||
analysing clip rectangles. */
|
||||
IntRect bounds(offset, size);
|
||||
bounds.IntersectRect(bounds,
|
||||
IntRect(0, 0, cairo_xlib_surface_get_width(target),
|
||||
cairo_xlib_surface_get_height(target)));
|
||||
|
||||
bool needs_clip = true;
|
||||
IntRect rectangles[MAX_STATIC_CLIP_RECTANGLES];
|
||||
int rect_count = 0;
|
||||
|
||||
/* Check that the clip is rectangular and aligned on unit boundaries. */
|
||||
/* Temporarily set the matrix for _get_rectangular_clip. It's basically
|
||||
the identity matrix, but we must adjust for the fact that our
|
||||
offset-rect is in device coordinates. */
|
||||
cairo_identity_matrix(cr);
|
||||
cairo_translate(cr, -device_offset_x, -device_offset_y);
|
||||
bool have_rectangular_clip = _get_rectangular_clip(
|
||||
cr, bounds, &needs_clip, rectangles, max_rectangles, &rect_count);
|
||||
cairo_set_matrix(cr, &matrix);
|
||||
if (!have_rectangular_clip) return false;
|
||||
|
||||
/* Stop now if everything is clipped out */
|
||||
if (needs_clip && rect_count == 0) return true;
|
||||
|
||||
/* Check that the screen is supported.
|
||||
Visuals belong to screens, so, if alternate visuals are not supported,
|
||||
then alternate screens cannot be supported. */
|
||||
bool supports_alternate_visual =
|
||||
(flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
|
||||
bool supports_alternate_screen =
|
||||
supports_alternate_visual && (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN);
|
||||
if (!supports_alternate_screen &&
|
||||
cairo_xlib_surface_get_screen(target) != screen) {
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: non-default screen");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that there is a visual */
|
||||
Visual* target_visual = cairo_xlib_surface_get_visual(target);
|
||||
if (!target_visual) {
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface");
|
||||
return false;
|
||||
}
|
||||
/* Check that the visual is supported */
|
||||
if (!supports_alternate_visual && target_visual != visual) {
|
||||
// Only the format of the visual is important (not the GLX properties)
|
||||
// for Xlib or XRender drawing.
|
||||
XRenderPictFormat* target_format =
|
||||
cairo_xlib_surface_get_xrender_format(target);
|
||||
if (!target_format ||
|
||||
(target_format !=
|
||||
XRenderFindVisualFormat(DisplayOfScreen(screen), visual))) {
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* we're good to go! */
|
||||
NATIVE_DRAWING_NOTE("TAKING FAST PATH\n");
|
||||
cairo_surface_flush(target);
|
||||
nsresult rv =
|
||||
DrawWithXlib(target, offset, rectangles, needs_clip ? rect_count : 0);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
cairo_surface_mark_dirty(target);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool VisualHasAlpha(Screen* screen, Visual* visual) {
|
||||
// There may be some other visuals format with alpha but usually this is
|
||||
// the only one we care about.
|
||||
return visual->c_class == TrueColor && visual->bits_per_rgb == 8 &&
|
||||
visual->red_mask == 0xff0000 && visual->green_mask == 0xff00 &&
|
||||
visual->blue_mask == 0xff &&
|
||||
gfxXlibSurface::DepthOfVisual(screen, visual) == 32;
|
||||
}
|
||||
|
||||
// Returns whether pixel conversion between visual and format is exact (in
|
||||
// both directions).
|
||||
static bool FormatConversionIsExact(Screen* screen, Visual* visual,
|
||||
XRenderPictFormat* format) {
|
||||
if (!format || visual->c_class != TrueColor ||
|
||||
format->type != PictTypeDirect ||
|
||||
gfxXlibSurface::DepthOfVisual(screen, visual) != format->depth)
|
||||
return false;
|
||||
|
||||
XRenderPictFormat* visualFormat =
|
||||
XRenderFindVisualFormat(DisplayOfScreen(screen), visual);
|
||||
|
||||
if (visualFormat->type != PictTypeDirect) return false;
|
||||
|
||||
const XRenderDirectFormat& a = visualFormat->direct;
|
||||
const XRenderDirectFormat& b = format->direct;
|
||||
return a.redMask == b.redMask && a.greenMask == b.greenMask &&
|
||||
a.blueMask == b.blueMask;
|
||||
}
|
||||
|
||||
// The 3 non-direct strategies described above.
|
||||
// The surface format and strategy are inter-dependent.
|
||||
enum DrawingMethod { eSimple, eCopyBackground, eAlphaExtraction };
|
||||
|
||||
static cairo_surface_t* CreateTempXlibSurface(
|
||||
cairo_surface_t* cairoTarget, DrawTarget* drawTarget, IntSize size,
|
||||
bool canDrawOverBackground, uint32_t flags, Screen* screen, Visual* visual,
|
||||
DrawingMethod* method) {
|
||||
NS_ASSERTION(cairoTarget || drawTarget, "Must have some type");
|
||||
|
||||
bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0;
|
||||
bool supportsAlternateVisual =
|
||||
(flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
|
||||
bool supportsAlternateScreen =
|
||||
supportsAlternateVisual &&
|
||||
(flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN);
|
||||
|
||||
cairo_surface_type_t cairoTargetType =
|
||||
cairoTarget ? cairo_surface_get_type(cairoTarget)
|
||||
: (cairo_surface_type_t)0xFF;
|
||||
|
||||
Screen* target_screen = cairoTargetType == CAIRO_SURFACE_TYPE_XLIB
|
||||
? cairo_xlib_surface_get_screen(cairoTarget)
|
||||
: screen;
|
||||
|
||||
// When the background has an alpha channel, we need to draw with an alpha
|
||||
// channel anyway, so there is no need to copy the background. If
|
||||
// doCopyBackground is set here, we'll also need to check below that the
|
||||
// background can copied without any loss in format conversions.
|
||||
bool doCopyBackground =
|
||||
!drawIsOpaque && canDrawOverBackground && cairoTarget &&
|
||||
cairo_surface_get_content(cairoTarget) == CAIRO_CONTENT_COLOR;
|
||||
|
||||
if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) {
|
||||
// Prefer a visual on the target screen.
|
||||
// (If !drawIsOpaque, we'll need doCopyBackground or an alpha channel.)
|
||||
visual = DefaultVisualOfScreen(target_screen);
|
||||
screen = target_screen;
|
||||
|
||||
} else if (doCopyBackground || (supportsAlternateVisual && drawIsOpaque)) {
|
||||
// Analyse the pixel formats either to check whether we can
|
||||
// doCopyBackground or to see if we can find a better visual for
|
||||
// opaque drawing.
|
||||
Visual* target_visual = nullptr;
|
||||
XRenderPictFormat* target_format = nullptr;
|
||||
if (cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) {
|
||||
target_visual = cairo_xlib_surface_get_visual(cairoTarget);
|
||||
target_format = cairo_xlib_surface_get_xrender_format(cairoTarget);
|
||||
} else if (cairoTargetType == CAIRO_SURFACE_TYPE_IMAGE || drawTarget) {
|
||||
gfxImageFormat imageFormat =
|
||||
drawTarget ? SurfaceFormatToImageFormat(drawTarget->GetFormat())
|
||||
: CairoFormatToGfxFormat(
|
||||
cairo_image_surface_get_format(cairoTarget));
|
||||
target_visual = gfxXlibSurface::FindVisual(screen, imageFormat);
|
||||
Display* dpy = DisplayOfScreen(screen);
|
||||
if (target_visual) {
|
||||
target_format = XRenderFindVisualFormat(dpy, target_visual);
|
||||
} else {
|
||||
target_format = gfxXlibSurface::FindRenderFormat(dpy, imageFormat);
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsAlternateVisual &&
|
||||
(supportsAlternateScreen || screen == target_screen)) {
|
||||
if (target_visual) {
|
||||
visual = target_visual;
|
||||
screen = target_screen;
|
||||
}
|
||||
}
|
||||
// Could try harder to match formats across screens for background
|
||||
// copying when !supportsAlternateScreen, if we cared. Preferably
|
||||
// we'll find a visual below with an alpha channel anyway; if so, the
|
||||
// background won't need to be copied.
|
||||
|
||||
if (doCopyBackground && visual != target_visual &&
|
||||
!FormatConversionIsExact(screen, visual, target_format)) {
|
||||
doCopyBackground = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsAlternateVisual && !drawIsOpaque &&
|
||||
(screen != target_screen ||
|
||||
!(doCopyBackground || VisualHasAlpha(screen, visual)))) {
|
||||
// Try to find a visual with an alpha channel.
|
||||
Screen* visualScreen = supportsAlternateScreen ? target_screen : screen;
|
||||
Visual* argbVisual = gfxXlibSurface::FindVisual(
|
||||
visualScreen, SurfaceFormat::A8R8G8B8_UINT32);
|
||||
if (argbVisual) {
|
||||
visual = argbVisual;
|
||||
screen = visualScreen;
|
||||
} else if (!doCopyBackground &&
|
||||
gfxXlibSurface::DepthOfVisual(screen, visual) != 24) {
|
||||
// Will need to do alpha extraction; prefer a 24-bit visual.
|
||||
// No advantage in using the target screen.
|
||||
Visual* rgb24Visual =
|
||||
gfxXlibSurface::FindVisual(screen, SurfaceFormat::X8R8G8B8_UINT32);
|
||||
if (rgb24Visual) {
|
||||
visual = rgb24Visual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drawable drawable =
|
||||
(screen == target_screen && cairoTargetType == CAIRO_SURFACE_TYPE_XLIB)
|
||||
? cairo_xlib_surface_get_drawable(cairoTarget)
|
||||
: RootWindowOfScreen(screen);
|
||||
|
||||
cairo_surface_t* surface = gfxXlibSurface::CreateCairoSurface(
|
||||
screen, visual, IntSize(size.width, size.height), drawable);
|
||||
if (!surface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (drawIsOpaque ||
|
||||
cairo_surface_get_content(surface) == CAIRO_CONTENT_COLOR_ALPHA) {
|
||||
NATIVE_DRAWING_NOTE(drawIsOpaque ? ", SIMPLE OPAQUE\n"
|
||||
: ", SIMPLE WITH ALPHA");
|
||||
*method = eSimple;
|
||||
} else if (doCopyBackground) {
|
||||
NATIVE_DRAWING_NOTE(", COPY BACKGROUND\n");
|
||||
*method = eCopyBackground;
|
||||
} else {
|
||||
NATIVE_DRAWING_NOTE(", SLOW ALPHA EXTRACTION\n");
|
||||
*method = eAlphaExtraction;
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
bool gfxXlibNativeRenderer::DrawOntoTempSurface(
|
||||
cairo_surface_t* tempXlibSurface, IntPoint offset) {
|
||||
cairo_surface_flush(tempXlibSurface);
|
||||
/* no clipping is needed because the callback can't draw outside the native
|
||||
surface anyway */
|
||||
nsresult rv = DrawWithXlib(tempXlibSurface, offset, nullptr, 0);
|
||||
cairo_surface_mark_dirty(tempXlibSurface);
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxImageSurface> CopyXlibSurfaceToImage(
|
||||
cairo_surface_t* tempXlibSurface, IntSize size, gfxImageFormat format) {
|
||||
RefPtr<gfxImageSurface> result = new gfxImageSurface(size, format);
|
||||
|
||||
cairo_t* copyCtx = cairo_create(result->CairoSurface());
|
||||
cairo_set_source_surface(copyCtx, tempXlibSurface, 0, 0);
|
||||
cairo_set_operator(copyCtx, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint(copyCtx);
|
||||
cairo_destroy(copyCtx);
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void gfxXlibNativeRenderer::Draw(gfxContext* ctx, IntSize size, uint32_t flags,
|
||||
Screen* screen, Visual* visual) {
|
||||
Matrix matrix = ctx->CurrentMatrix();
|
||||
|
||||
// We can only draw direct or onto a copied background if pixels align and
|
||||
// native drawing is compatible with the current operator. (The matrix is
|
||||
// actually also pixel-exact for flips and right-angle rotations, which
|
||||
// would permit copying the background but not drawing direct.)
|
||||
bool matrixIsIntegerTranslation = !matrix.HasNonIntegerTranslation();
|
||||
bool canDrawOverBackground =
|
||||
matrixIsIntegerTranslation && ctx->CurrentOp() == CompositionOp::OP_OVER;
|
||||
|
||||
// The padding of 0.5 for non-pixel-exact transformations used here is
|
||||
// the same as what _cairo_pattern_analyze_filter uses.
|
||||
const gfxFloat filterRadius = 0.5;
|
||||
gfxRect affectedRect(0.0, 0.0, size.width, size.height);
|
||||
if (!matrixIsIntegerTranslation) {
|
||||
// The filter footprint means that the affected rectangle is a
|
||||
// little larger than the drawingRect;
|
||||
affectedRect.Inflate(filterRadius);
|
||||
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: matrix not integer translation");
|
||||
} else if (!canDrawOverBackground) {
|
||||
NATIVE_DRAWING_NOTE("FALLBACK: unsupported operator");
|
||||
}
|
||||
|
||||
DrawTarget* drawTarget = ctx->GetDrawTarget();
|
||||
if (!drawTarget) {
|
||||
gfxCriticalError() << "gfxContext without a DrawTarget";
|
||||
return;
|
||||
}
|
||||
|
||||
// Clipping to the region affected by drawing allows us to consider only
|
||||
// the portions of the clip region that will be affected by drawing.
|
||||
gfxRect clipExtents;
|
||||
{
|
||||
gfxContextAutoSaveRestore autoSR(ctx);
|
||||
ctx->Clip(affectedRect);
|
||||
|
||||
clipExtents = ctx->GetClipExtents();
|
||||
if (clipExtents.IsEmpty()) {
|
||||
return; // nothing to do
|
||||
}
|
||||
if (canDrawOverBackground &&
|
||||
DrawDirect(drawTarget, size, flags, screen, visual)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IntRect drawingRect(IntPoint(0, 0), size);
|
||||
// Drawing need only be performed within the clip extents
|
||||
// (and padding for the filter).
|
||||
if (!matrixIsIntegerTranslation) {
|
||||
// The source surface may need to be a little larger than the clip
|
||||
// extents due to the filter footprint.
|
||||
clipExtents.Inflate(filterRadius);
|
||||
}
|
||||
clipExtents.RoundOut();
|
||||
|
||||
IntRect intExtents(int32_t(clipExtents.X()), int32_t(clipExtents.Y()),
|
||||
int32_t(clipExtents.Width()),
|
||||
int32_t(clipExtents.Height()));
|
||||
drawingRect.IntersectRect(drawingRect, intExtents);
|
||||
|
||||
gfxPoint offset(drawingRect.x, drawingRect.y);
|
||||
|
||||
DrawingMethod method;
|
||||
Matrix dtTransform = drawTarget->GetTransform();
|
||||
gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
|
||||
cairo_t* cairo = static_cast<cairo_t*>(
|
||||
drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
|
||||
cairo_surface_t* cairoTarget =
|
||||
cairo ? cairo_get_group_target(cairo) : nullptr;
|
||||
cairo_surface_t* tempXlibSurface = CreateTempXlibSurface(
|
||||
cairoTarget, drawTarget, size, canDrawOverBackground, flags, screen,
|
||||
visual, &method);
|
||||
if (!tempXlibSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
|
||||
if (!drawIsOpaque) {
|
||||
cairo_t* tmpCtx = cairo_create(tempXlibSurface);
|
||||
if (method == eCopyBackground) {
|
||||
NS_ASSERTION(cairoTarget,
|
||||
"eCopyBackground only used when there's a cairoTarget");
|
||||
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
|
||||
gfxPoint pt = -(offset + deviceTranslation);
|
||||
cairo_set_source_surface(tmpCtx, cairoTarget, pt.x, pt.y);
|
||||
// The copy from the tempXlibSurface to the target context should
|
||||
// use operator SOURCE, but that would need a mask to bound the
|
||||
// operation. Here we only copy opaque backgrounds so operator
|
||||
// OVER will behave like SOURCE masked by the surface.
|
||||
NS_ASSERTION(
|
||||
cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR,
|
||||
"Don't copy background with a transparent surface");
|
||||
} else {
|
||||
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_CLEAR);
|
||||
}
|
||||
cairo_paint(tmpCtx);
|
||||
cairo_destroy(tmpCtx);
|
||||
}
|
||||
|
||||
if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
|
||||
cairo_surface_destroy(tempXlibSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
SurfaceFormat moz2DFormat =
|
||||
cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR
|
||||
? SurfaceFormat::B8G8R8A8
|
||||
: SurfaceFormat::B8G8R8X8;
|
||||
if (method != eAlphaExtraction) {
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
Factory::CreateSourceSurfaceForCairoSurface(tempXlibSurface, size,
|
||||
moz2DFormat);
|
||||
if (sourceSurface) {
|
||||
drawTarget->DrawSurface(sourceSurface,
|
||||
Rect(offset.x, offset.y, size.width, size.height),
|
||||
Rect(0, 0, size.width, size.height));
|
||||
}
|
||||
cairo_surface_destroy(tempXlibSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfxImageSurface> blackImage = CopyXlibSurfaceToImage(
|
||||
tempXlibSurface, size, SurfaceFormat::A8R8G8B8_UINT32);
|
||||
|
||||
cairo_t* tmpCtx = cairo_create(tempXlibSurface);
|
||||
cairo_set_source_rgba(tmpCtx, 1.0, 1.0, 1.0, 1.0);
|
||||
cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint(tmpCtx);
|
||||
cairo_destroy(tmpCtx);
|
||||
DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft());
|
||||
RefPtr<gfxImageSurface> whiteImage = CopyXlibSurfaceToImage(
|
||||
tempXlibSurface, size, SurfaceFormat::X8R8G8B8_UINT32);
|
||||
|
||||
if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
|
||||
whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
|
||||
if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
|
||||
cairo_surface_destroy(tempXlibSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
gfxASurface* paintSurface = blackImage;
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
Factory::CreateSourceSurfaceForCairoSurface(
|
||||
paintSurface->CairoSurface(), size, moz2DFormat);
|
||||
if (sourceSurface) {
|
||||
drawTarget->DrawSurface(sourceSurface,
|
||||
Rect(offset.x, offset.y, size.width, size.height),
|
||||
Rect(0, 0, size.width, size.height));
|
||||
}
|
||||
}
|
||||
cairo_surface_destroy(tempXlibSurface);
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFXXLIBNATIVERENDER_H_
|
||||
#define GFXXLIBNATIVERENDER_H_
|
||||
|
||||
#include "nsPoint.h"
|
||||
#include "nsRect.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
class gfxASurface;
|
||||
class gfxContext;
|
||||
typedef struct _cairo cairo_t;
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
|
||||
/**
|
||||
* This class lets us take code that draws into an X drawable and lets us
|
||||
* use it to draw into any Thebes context. The user should subclass this class,
|
||||
* override DrawWithXib, and then call Draw(). The drawing will be subjected
|
||||
* to all Thebes transformations, clipping etc.
|
||||
*/
|
||||
class gfxXlibNativeRenderer {
|
||||
public:
|
||||
/**
|
||||
* Perform the native drawing.
|
||||
* @param surface the cairo_surface_t for drawing. Must be a
|
||||
* cairo_xlib_surface_t. The extents of this surface do not necessarily cover
|
||||
* the entire rectangle with size provided to Draw().
|
||||
* @param offset draw at this offset into the given drawable
|
||||
* @param clipRects an array of rectangles; clip to the union.
|
||||
* Any rectangles provided will be contained by the
|
||||
* rectangle with size provided to Draw and by the
|
||||
* surface extents.
|
||||
* @param numClipRects the number of rects in the array, or zero if
|
||||
* no clipping is required.
|
||||
*/
|
||||
virtual nsresult DrawWithXlib(cairo_surface_t* surface,
|
||||
mozilla::gfx::IntPoint offset,
|
||||
mozilla::gfx::IntRect* clipRects,
|
||||
uint32_t numClipRects) = 0;
|
||||
|
||||
enum {
|
||||
// If set, then Draw() is opaque, i.e., every pixel in the intersection
|
||||
// of the clipRect and (offset.x,offset.y,bounds.width,bounds.height)
|
||||
// will be set and there is no dependence on what the existing pixels
|
||||
// in the drawable are set to.
|
||||
DRAW_IS_OPAQUE = 0x01,
|
||||
// If set, then numClipRects can be zero or one
|
||||
DRAW_SUPPORTS_CLIP_RECT = 0x04,
|
||||
// If set, then numClipRects can be any value. If neither this
|
||||
// nor CLIP_RECT are set, then numClipRects will be zero
|
||||
DRAW_SUPPORTS_CLIP_LIST = 0x08,
|
||||
// If set, then the surface in the callback may have any visual;
|
||||
// otherwise the pixels will have the same format as the visual
|
||||
// passed to 'Draw'.
|
||||
DRAW_SUPPORTS_ALTERNATE_VISUAL = 0x10,
|
||||
// If set, then the Screen 'screen' in the callback can be different
|
||||
// from the default Screen of the display passed to 'Draw' and can be
|
||||
// on a different display.
|
||||
DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
|
||||
};
|
||||
|
||||
/**
|
||||
* @param flags see above
|
||||
* @param size the size of the rectangle being drawn;
|
||||
* the caller guarantees that drawing will not extend beyond the rectangle
|
||||
* (0,0,size.width,size.height).
|
||||
* @param screen a Screen to use for the drawing if ctx doesn't have one.
|
||||
* @param visual a Visual to use for the drawing if ctx doesn't have one.
|
||||
* @param result if non-null, we will try to capture a copy of the
|
||||
* rendered image into a surface similar to the surface of ctx; if
|
||||
* successful, a pointer to the new gfxASurface is stored in *resultSurface,
|
||||
* otherwise *resultSurface is set to nullptr.
|
||||
*/
|
||||
void Draw(gfxContext* ctx, mozilla::gfx::IntSize size, uint32_t flags,
|
||||
Screen* screen, Visual* visual);
|
||||
|
||||
private:
|
||||
bool DrawDirect(mozilla::gfx::DrawTarget* aDT, mozilla::gfx::IntSize bounds,
|
||||
uint32_t flags, Screen* screen, Visual* visual);
|
||||
|
||||
bool DrawCairo(cairo_t* cr, mozilla::gfx::IntSize size, uint32_t flags,
|
||||
Screen* screen, Visual* visual);
|
||||
|
||||
void DrawFallback(mozilla::gfx::DrawTarget* dt, gfxContext* ctx,
|
||||
gfxASurface* aSurface, mozilla::gfx::IntSize& size,
|
||||
mozilla::gfx::IntRect& drawingRect,
|
||||
bool canDrawOverBackground, uint32_t flags, Screen* screen,
|
||||
Visual* visual);
|
||||
|
||||
bool DrawOntoTempSurface(cairo_surface_t* tempXlibSurface,
|
||||
mozilla::gfx::IntPoint offset);
|
||||
};
|
||||
|
||||
#endif /*GFXXLIBNATIVERENDER_H_*/
|
|
@ -112,7 +112,6 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
|||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
||||
EXPORTS += [
|
||||
"gfxFT2FontBase.h",
|
||||
"gfxGdkNativeRenderer.h",
|
||||
"gfxPlatformGtk.h",
|
||||
]
|
||||
EXPORTS.mozilla.gfx += [
|
||||
|
@ -123,7 +122,6 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
|||
"gfxFcPlatformFontList.cpp",
|
||||
"gfxFT2FontBase.cpp",
|
||||
"gfxFT2Utils.cpp",
|
||||
"gfxGdkNativeRenderer.cpp",
|
||||
"gfxPlatformGtk.cpp",
|
||||
"PrintTargetPDF.cpp",
|
||||
"PrintTargetPS.cpp",
|
||||
|
@ -131,14 +129,12 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
|||
|
||||
if CONFIG["MOZ_X11"]:
|
||||
EXPORTS += [
|
||||
"gfxXlibNativeRenderer.h",
|
||||
"gfxXlibSurface.h",
|
||||
]
|
||||
EXPORTS.mozilla.gfx += [
|
||||
"XlibDisplay.h",
|
||||
]
|
||||
SOURCES += [
|
||||
"gfxXlibNativeRenderer.cpp",
|
||||
"gfxXlibSurface.cpp",
|
||||
"XlibDisplay.cpp",
|
||||
]
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxGdkNativeRenderer.h"
|
||||
#include "mozilla/gfx/BorrowedContext.h"
|
||||
#include "mozilla/gfx/HelpersCairo.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче