mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-28 17:23:09 +03:00
6807b4208a
NetSurf includes are now done with ""s and other system includes with <>s as C intended. The scandeps tool has been updated to only look for ""ed includes, and to verify that the files exist in the tree before adding them to the dependency lines. The depend rule has therefore been augmented to make sure the autogenerated files are built before it is run. This is untested under self-hosted RISC OS builds. All else tested and works. svn path=/trunk/netsurf/; revision=3307
462 lines
11 KiB
C
462 lines
11 KiB
C
/*
|
|
* This file is part of NetSurf, http://netsurf-browser.org/
|
|
* Licensed under the GNU General Public License,
|
|
* http://www.opensource.org/licenses/gpl-license
|
|
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
|
|
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
|
|
*/
|
|
|
|
/** \file
|
|
* Target independent plotting (GDK / GTK+ and Cairo implementation).
|
|
* Can use either GDK drawing primitives (which are mostly passed straight
|
|
* to X to process, and thus accelerated) or Cairo drawing primitives (much
|
|
* higher quality, not accelerated). Cairo's fast enough, so it defaults
|
|
* to using it if it is available. It does this by checking for the
|
|
* CAIRO_VERSION define that the cairo headers set.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <gdk/gdk.h>
|
|
#include <gtk/gtk.h>
|
|
#include "desktop/plotters.h"
|
|
#include "gtk/font_pango.h"
|
|
#include "gtk/gtk_plotters.h"
|
|
#include "gtk/gtk_scaffolding.h"
|
|
#include "render/font.h"
|
|
#include "utils/log.h"
|
|
#include "desktop/options.h"
|
|
#include "gtk/options.h"
|
|
#include "gtk/gtk_bitmap.h"
|
|
|
|
GtkWidget *current_widget;
|
|
GdkDrawable *current_drawable;
|
|
GdkGC *current_gc;
|
|
#ifdef CAIRO_VERSION
|
|
cairo_t *current_cr;
|
|
#endif
|
|
|
|
static bool nsgtk_plot_clg(colour c);
|
|
static bool nsgtk_plot_rectangle(int x0, int y0, int width, int height,
|
|
int line_width, colour c, bool dotted, bool dashed);
|
|
static bool nsgtk_plot_line(int x0, int y0, int x1, int y1, int width,
|
|
colour c, bool dotted, bool dashed);
|
|
static bool nsgtk_plot_polygon(int *p, unsigned int n, colour fill);
|
|
static bool nsgtk_plot_fill(int x0, int y0, int x1, int y1, colour c);
|
|
static bool nsgtk_plot_clip(int clip_x0, int clip_y0,
|
|
int clip_x1, int clip_y1);
|
|
static bool nsgtk_plot_text(int x, int y, struct css_style *style,
|
|
const char *text, size_t length, colour bg, colour c);
|
|
static bool nsgtk_plot_disc(int x, int y, int radius, colour c, bool filled);
|
|
static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2,
|
|
colour c);
|
|
static bool nsgtk_plot_bitmap(int x, int y, int width, int height,
|
|
struct bitmap *bitmap, colour bg);
|
|
static bool nsgtk_plot_bitmap_tile(int x, int y, int width, int height,
|
|
struct bitmap *bitmap, colour bg,
|
|
bool repeat_x, bool repeat_y);
|
|
static void nsgtk_set_solid(void); /**< Set for drawing solid lines */
|
|
static void nsgtk_set_dotted(void); /**< Set for drawing dotted lines */
|
|
static void nsgtk_set_dashed(void); /**< Set for drawing dashed lines */
|
|
|
|
static GdkRectangle cliprect;
|
|
static float nsgtk_plot_scale = 1.0;
|
|
|
|
struct plotter_table plot;
|
|
|
|
const struct plotter_table nsgtk_plotters = {
|
|
nsgtk_plot_clg,
|
|
nsgtk_plot_rectangle,
|
|
nsgtk_plot_line,
|
|
nsgtk_plot_polygon,
|
|
nsgtk_plot_fill,
|
|
nsgtk_plot_clip,
|
|
nsgtk_plot_text,
|
|
nsgtk_plot_disc,
|
|
nsgtk_plot_arc,
|
|
nsgtk_plot_bitmap,
|
|
nsgtk_plot_bitmap_tile,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
bool nsgtk_plot_clg(colour c)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool nsgtk_plot_rectangle(int x0, int y0, int width, int height,
|
|
int line_width, colour c, bool dotted, bool dashed)
|
|
{
|
|
nsgtk_set_colour(c);
|
|
if (dotted)
|
|
nsgtk_set_dotted();
|
|
else if (dashed)
|
|
nsgtk_set_dashed();
|
|
else
|
|
nsgtk_set_solid();
|
|
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
if (line_width == 0)
|
|
line_width = 1;
|
|
|
|
cairo_set_line_width(current_cr, line_width);
|
|
cairo_rectangle(current_cr, x0, y0, width, height);
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
gdk_draw_rectangle(current_drawable, current_gc,
|
|
FALSE, x0, y0, width, height);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_line(int x0, int y0, int x1, int y1, int width,
|
|
colour c, bool dotted, bool dashed)
|
|
{
|
|
nsgtk_set_colour(c);
|
|
if (dotted)
|
|
nsgtk_set_dotted();
|
|
else if (dashed)
|
|
nsgtk_set_dashed();
|
|
else
|
|
nsgtk_set_solid();
|
|
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
if (width == 0)
|
|
width = 1;
|
|
|
|
cairo_set_line_width(current_cr, width);
|
|
cairo_move_to(current_cr, x0, y0 - 0.5);
|
|
cairo_line_to(current_cr, x1, y1 - 0.5);
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
gdk_draw_line(current_drawable, current_gc,
|
|
x0, y0, x1, y1);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_polygon(int *p, unsigned int n, colour fill)
|
|
{
|
|
unsigned int i;
|
|
|
|
nsgtk_set_colour(fill);
|
|
nsgtk_set_solid();
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
cairo_set_line_width(current_cr, 0);
|
|
cairo_move_to(current_cr, p[0], p[1]);
|
|
for (i = 1; i != n; i++) {
|
|
cairo_line_to(current_cr, p[i * 2], p[i * 2 + 1]);
|
|
}
|
|
cairo_fill(current_cr);
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
{
|
|
GdkPoint q[n];
|
|
for (i = 0; i != n; i++) {
|
|
q[i].x = p[i * 2];
|
|
q[i].y = p[i * 2 + 1];
|
|
}
|
|
gdk_draw_polygon(current_drawable, current_gc,
|
|
TRUE, q, n);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_fill(int x0, int y0, int x1, int y1, colour c)
|
|
{
|
|
nsgtk_set_colour(c);
|
|
nsgtk_set_solid();
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
cairo_set_line_width(current_cr, 0);
|
|
cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0);
|
|
cairo_fill(current_cr);
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
gdk_draw_rectangle(current_drawable, current_gc,
|
|
TRUE, x0, y0, x1 - x0, y1 - y0);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_clip(int clip_x0, int clip_y0,
|
|
int clip_x1, int clip_y1)
|
|
{
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
cairo_reset_clip(current_cr);
|
|
cairo_rectangle(current_cr, clip_x0, clip_y0,
|
|
clip_x1 - clip_x0, clip_y1 - clip_y0);
|
|
cairo_clip(current_cr);
|
|
}
|
|
#endif
|
|
cliprect.x = clip_x0;
|
|
cliprect.y = clip_y0;
|
|
cliprect.width = clip_x1 - clip_x0;
|
|
cliprect.height = clip_y1 - clip_y0;
|
|
gdk_gc_set_clip_rectangle(current_gc, &cliprect);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_text(int x, int y, struct css_style *style,
|
|
const char *text, size_t length, colour bg, colour c)
|
|
{
|
|
return nsfont_paint(style, text, length, x, y, c);
|
|
}
|
|
|
|
|
|
bool nsgtk_plot_disc(int x, int y, int radius, colour c, bool filled)
|
|
{
|
|
nsgtk_set_colour(c);
|
|
nsgtk_set_solid();
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
if (filled)
|
|
cairo_set_line_width(current_cr, 0);
|
|
else
|
|
cairo_set_line_width(current_cr, 1);
|
|
|
|
cairo_arc(current_cr, x, y, radius, 0, M_PI * 2);
|
|
|
|
if (filled)
|
|
cairo_fill(current_cr);
|
|
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
gdk_draw_arc(current_drawable, current_gc,
|
|
filled ? TRUE : FALSE, x - (radius), y - radius,
|
|
radius * 2, radius * 2,
|
|
0,
|
|
360 * 64);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c)
|
|
{
|
|
nsgtk_set_colour(c);
|
|
nsgtk_set_solid();
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo) {
|
|
cairo_set_line_width(current_cr, 1);
|
|
cairo_arc(current_cr, x, y, radius,
|
|
(angle1 + 90) * (M_PI / 180),
|
|
(angle2 + 90) * (M_PI / 180));
|
|
cairo_stroke(current_cr);
|
|
} else
|
|
#endif
|
|
gdk_draw_arc(current_drawable, current_gc,
|
|
FALSE, x - (radius), y - radius,
|
|
radius * 2, radius * 2,
|
|
angle1 * 64, angle2 * 64);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
|
|
GdkPixbuf *pixbuf, colour bg)
|
|
{
|
|
/* XXX: This currently ignores the background colour supplied.
|
|
* Does this matter?
|
|
*/
|
|
|
|
if (width == 0 || height == 0)
|
|
return true;
|
|
|
|
if (gdk_pixbuf_get_width(pixbuf) == width &&
|
|
gdk_pixbuf_get_height(pixbuf) == height) {
|
|
gdk_draw_pixbuf(current_drawable, current_gc,
|
|
pixbuf,
|
|
0, 0,
|
|
x, y,
|
|
width, height,
|
|
GDK_RGB_DITHER_MAX, 0, 0);
|
|
|
|
} else {
|
|
GdkPixbuf *scaled;
|
|
scaled = gdk_pixbuf_scale_simple(pixbuf,
|
|
width, height,
|
|
option_render_resample ? GDK_INTERP_BILINEAR
|
|
: GDK_INTERP_NEAREST);
|
|
if (!scaled)
|
|
return false;
|
|
|
|
gdk_draw_pixbuf(current_drawable, current_gc,
|
|
scaled,
|
|
0, 0,
|
|
x, y,
|
|
width, height,
|
|
GDK_RGB_DITHER_MAX, 0, 0);
|
|
|
|
g_object_unref(scaled);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool nsgtk_plot_bitmap(int x, int y, int width, int height,
|
|
struct bitmap *bitmap, colour bg)
|
|
{
|
|
GdkPixbuf *pixbuf = gtk_bitmap_get_primary(bitmap);
|
|
return nsgtk_plot_pixbuf(x, y, width, height, pixbuf, bg);
|
|
}
|
|
|
|
bool nsgtk_plot_bitmap_tile(int x, int y, int width, int height,
|
|
struct bitmap *bitmap, colour bg,
|
|
bool repeat_x, bool repeat_y)
|
|
{
|
|
int doneheight = 0, donewidth = 0;
|
|
GdkPixbuf *primary;
|
|
GdkPixbuf *pretiled;
|
|
|
|
if (!(repeat_x || repeat_y)) {
|
|
/* Not repeating at all, so just pass it on */
|
|
return nsgtk_plot_bitmap(x,y,width,height,bitmap,bg);
|
|
}
|
|
|
|
if (repeat_x && !repeat_y)
|
|
pretiled = gtk_bitmap_get_pretile_x(bitmap);
|
|
if (repeat_x && repeat_y)
|
|
pretiled = gtk_bitmap_get_pretile_xy(bitmap);
|
|
if (!repeat_x && repeat_y)
|
|
pretiled = gtk_bitmap_get_pretile_y(bitmap);
|
|
primary = gtk_bitmap_get_primary(bitmap);
|
|
/* use the primary and pretiled widths to scale the w/h provided */
|
|
width *= gdk_pixbuf_get_width(pretiled);
|
|
width /= gdk_pixbuf_get_width(primary);
|
|
height *= gdk_pixbuf_get_height(pretiled);
|
|
height /= gdk_pixbuf_get_height(primary);
|
|
|
|
if (y > cliprect.y)
|
|
doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
|
|
else
|
|
doneheight = y;
|
|
|
|
while (doneheight < (cliprect.y + cliprect.height)) {
|
|
if (x > cliprect.x)
|
|
donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
|
|
else
|
|
donewidth = x;
|
|
while (donewidth < (cliprect.x + cliprect.width)) {
|
|
nsgtk_plot_pixbuf(donewidth, doneheight,
|
|
width, height, pretiled, bg);
|
|
donewidth += width;
|
|
if (!repeat_x) break;
|
|
}
|
|
doneheight += height;
|
|
if (!repeat_y) break;
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
void nsgtk_set_colour(colour c)
|
|
{
|
|
int r, g, b;
|
|
GdkColor colour;
|
|
|
|
r = c & 0xff;
|
|
g = (c & 0xff00) >> 8;
|
|
b = (c & 0xff0000) >> 16;
|
|
|
|
colour.red = r | (r << 8);
|
|
colour.green = g | (g << 8);
|
|
colour.blue = b | (b << 8);
|
|
colour.pixel = (r << 16) | (g << 8) | b;
|
|
|
|
gdk_color_alloc(gdk_colormap_get_system(),
|
|
&colour);
|
|
gdk_gc_set_foreground(current_gc, &colour);
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo)
|
|
cairo_set_source_rgba(current_cr, r / 255.0,
|
|
g / 255.0, b / 255.0, 1.0);
|
|
#endif
|
|
}
|
|
|
|
void nsgtk_set_solid()
|
|
{
|
|
#ifdef CAIRO_VERSION
|
|
double dashes = 0;
|
|
if (option_render_cairo)
|
|
cairo_set_dash(current_cr, &dashes, 0, 0);
|
|
else
|
|
#endif
|
|
gdk_gc_set_line_attributes(current_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
|
|
GDK_JOIN_MITER);
|
|
}
|
|
|
|
void nsgtk_set_dotted()
|
|
{
|
|
double cdashes = 1;
|
|
gint8 dashes[] = { 1, 1 };
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo)
|
|
cairo_set_dash(current_cr, &cdashes, 1, 0);
|
|
else
|
|
#endif
|
|
{
|
|
gdk_gc_set_dashes(current_gc, 0, dashes, 2);
|
|
gdk_gc_set_line_attributes(current_gc, 1, GDK_LINE_ON_OFF_DASH,
|
|
GDK_CAP_BUTT, GDK_JOIN_MITER);
|
|
}
|
|
}
|
|
|
|
void nsgtk_set_dashed()
|
|
{
|
|
double cdashes = 3;
|
|
gint8 dashes[] = { 3, 3 };
|
|
#ifdef CAIRO_VERSION
|
|
if (option_render_cairo)
|
|
cairo_set_dash(current_cr, &cdashes, 1, 0);
|
|
else
|
|
#endif
|
|
{
|
|
gdk_gc_set_dashes(current_gc, 0, dashes, 2);
|
|
gdk_gc_set_line_attributes(current_gc, 1, GDK_LINE_ON_OFF_DASH,
|
|
GDK_CAP_BUTT, GDK_JOIN_MITER);
|
|
}
|
|
}
|
|
|
|
void nsgtk_plot_set_scale(float s)
|
|
{
|
|
nsgtk_plot_scale = s;
|
|
}
|
|
|
|
float nsgtk_plot_get_scale(void)
|
|
{
|
|
return nsgtk_plot_scale;
|
|
}
|
|
|
|
/** Plot a caret. It is assumed that the plotters have been set up. */
|
|
void nsgtk_plot_caret(int x, int y, int h)
|
|
{
|
|
GdkColor colour;
|
|
|
|
colour.red = 0;
|
|
colour.green = 0;
|
|
colour.blue = 0;
|
|
colour.pixel = 0;
|
|
gdk_color_alloc(gdk_colormap_get_system(),
|
|
&colour);
|
|
gdk_gc_set_foreground(current_gc, &colour);
|
|
|
|
gdk_draw_line(current_drawable, current_gc,
|
|
x, y,
|
|
x, y + h - 1);
|
|
}
|
|
|