Put it into CVS.

Put it into CVS.
This commit is contained in:
Elliot Lee 2000-05-31 21:50:38 +00:00
parent 85e7a89b13
commit c496211676
51 changed files with 22169 additions and 0 deletions

8
gdk/linux-fb/.cvsignore Normal file
View File

@ -0,0 +1,8 @@
*.lo
Makefile
Makefile.in
.deps
_libs
.libs
libgdk-x11.la
gxid

61
gdk/linux-fb/Makefile.am Normal file
View File

@ -0,0 +1,61 @@
## Process this file with automake to produce Makefile.in
INCLUDES = @STRIP_BEGIN@ \
-DG_LOG_DOMAIN=\"Gdk\" \
-I$(top_srcdir) \
-I$(top_srcdir)/gdk \
-I$(top_builddir)/gdk \
@GTK_DEBUG_FLAGS@ \
@GTK_XIM_FLAGS@ \
@GTK_LOCALE_FLAGS@ \
@GLIB_CFLAGS@ \
@STRIP_END@
LDFLAGS = @STRIP_BEGIN@ \
@GLIB_LIBS@ \
-L/gnome2/lib \
-lt1 \
-lm \
@STRIP_END@
lib_LTLIBRARIES = libgdk-fb.la
noinst_PROGRAMS=test-fb
test_fb_LDFLAGS=../libgdk.la libgdk-fb.la
libgdk_fb_la_SOURCES = \
gdkcolor-fb.c \
gdkcursor-fb.c \
gdkdnd-fb.c \
gdkdrawable-fb2.c \
gdkfont-fb.c \
gdkgc-fb.c \
gdkgeometry-fb.c \
gdkglobals-fb.c \
gdkim-fb.c \
gdkimage-fb.c \
gdkinput.c \
gdkmain-fb.c \
gdkpixmap-fb.c \
gdkproperty-fb.c \
gdkpolyreg-generic.c \
gdkregion-generic.c \
gdkselection-fb.c \
gdkvisual-fb.c \
gdkwindow-fb.c \
gdkx.h \
gdkprivate-fb.h \
gdkinputprivate.h \
gdkinput-ps2.c \
gdkevents-fb.c \
miarc.c \
midash.c \
mifillarc.c \
mifpolycon.c \
mipoly.c \
mipolygen.c \
mipolyutil.c \
miwideline.c \
mizerclip.c \
mizerline.c \
mispans.c

3
gdk/linux-fb/TODO Normal file
View File

@ -0,0 +1,3 @@
. Fix CTree
. DnD?
. All the standard X cursors

759
gdk/linux-fb/gdkcolor-fb.c Normal file
View File

@ -0,0 +1,759 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <time.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include "gdkcolor.h"
#include "gdkprivate-fb.h"
static gint gdk_colormap_match_color (GdkColormap *cmap,
GdkColor *color,
const gchar *available);
GdkColormap*
gdk_colormap_new (GdkVisual *visual,
gint private_cmap)
{
GdkColormap *colormap;
GdkColormapPrivateFB *private;
GdkFBDisplay *fbd;
int i;
g_return_val_if_fail (visual != NULL, NULL);
private = g_new (GdkColormapPrivateFB, 1);
colormap = (GdkColormap*) private;
private->base.visual = visual;
private->base.ref_count = 1;
fbd = gdk_display;
private->hash = NULL;
colormap->size = visual->colormap_size;
colormap->colors = NULL;
switch (visual->type)
{
case GDK_VISUAL_STATIC_GRAY:
case GDK_VISUAL_STATIC_COLOR:
case GDK_VISUAL_GRAYSCALE:
case GDK_VISUAL_PSEUDO_COLOR:
private->info = g_new0 (GdkColorInfo, colormap->size);
colormap->colors = g_new (GdkColor, colormap->size);
private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
(GCompareFunc) gdk_color_equal);
if (private_cmap)
{
guint16 red[256], green[256], blue[256];
struct fb_cmap fbc = {0, 256};
fbc.red = red;
fbc.green = green;
fbc.blue = blue;
if(ioctl(fbd->fd, FBIOGETCMAP, &fbc))
g_error("ioctl(FBIOGETCMAP) failed");
for (i = 0; i < colormap->size; i++)
{
colormap->colors[i].pixel = i;
colormap->colors[i].red = red[i];
colormap->colors[i].green = green[i];
colormap->colors[i].blue = blue[i];
}
gdk_colormap_change (colormap, colormap->size);
}
break;
case GDK_VISUAL_DIRECT_COLOR:
g_error("NYI");
#if 0
colormap->colors = g_new (GdkColor, colormap->size);
size = 1 << visual->red_prec;
for (i = 0; i < size; i++)
colormap->colors[i].red = i * 65535 / (size - 1);
size = 1 << visual->green_prec;
for (i = 0; i < size; i++)
colormap->colors[i].green = i * 65535 / (size - 1);
size = 1 << visual->blue_prec;
for (i = 0; i < size; i++)
colormap->colors[i].blue = i * 65535 / (size - 1);
gdk_colormap_change (colormap, colormap->size);
#endif
break;
default:
g_assert_not_reached();
case GDK_VISUAL_TRUE_COLOR:
break;
}
return colormap;
}
void
_gdk_colormap_real_destroy (GdkColormap *colormap)
{
GdkColormapPrivateFB *private = (GdkColormapPrivateFB*) colormap;
if (private->hash)
g_hash_table_destroy (private->hash);
g_free (private->info);
g_free (colormap->colors);
g_free (colormap);
}
#define MIN_SYNC_TIME 2
void
gdk_colormap_sync (GdkColormap *colormap,
gboolean force)
{
}
GdkColormap*
gdk_colormap_get_system (void)
{
static GdkColormap *colormap = NULL;
if (!colormap)
{
guint16 red[256], green[256], blue[256];
struct fb_cmap fbc = {0, 256};
int i, r, g, b;
GdkVisual *visual = gdk_visual_get_system();
if(visual->type == GDK_VISUAL_GRAYSCALE
|| visual->type == GDK_VISUAL_PSEUDO_COLOR)
{
fbc.red = red;
fbc.green = green;
fbc.blue = blue;
switch(visual->type)
{
case GDK_VISUAL_GRAYSCALE:
for(i = 0; i < 256; i++)
red[i] = green[i] = blue[i] = i << 8;
i--;
red[i] = green[i] = blue[i] = 65535; /* Make it a true white */
break;
case GDK_VISUAL_PSEUDO_COLOR:
/* Color cube stolen from gdkrgb upon advice from Owen */
for(i = r = 0; r < 6; r++)
for(g = 0; g < 6; g++)
for(b = 0; b < 6; b++)
{
red[i] = r * 65535 / 5;
green[i] = g * 65535 / 5;
blue[i] = b * 65535 / 5;
i++;
}
g_assert(i == 216);
/* Fill in remaining space with grays */
for(i = 216; i < 256; i++)
{
red[i] = green[i] = blue[i] =
(i - 216) * 40;
}
/* Real white */
red[255] = green[255] = blue[255] = 65535;
break;
default:
break;
}
ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
}
colormap = gdk_colormap_new(visual, TRUE);
}
return colormap;
}
gint
gdk_colormap_get_system_size (void)
{
return 1 << (gdk_display->modeinfo.bits_per_pixel);
}
void
gdk_colormap_change (GdkColormap *colormap,
gint ncolors)
{
guint16 red[256], green[256], blue[256];
struct fb_cmap fbc = {0,256};
GdkColormapPrivateFB *private;
int i;
g_return_if_fail (colormap != NULL);
fbc.red = red;
fbc.green = green;
fbc.blue = blue;
private = (GdkColormapPrivateFB*) colormap;
switch (private->base.visual->type)
{
case GDK_VISUAL_GRAYSCALE:
for(i = 0; i < ncolors; i++)
{
red[i] = green[i] = blue[i] =
(colormap->colors[i].red +
colormap->colors[i].green +
colormap->colors[i].blue)/3;
}
ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
break;
case GDK_VISUAL_PSEUDO_COLOR:
for (i = 0; i < ncolors; i++)
{
red[i] = colormap->colors[i].red;
green[i] = colormap->colors[i].green;
blue[i] = colormap->colors[i].blue;
}
ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
break;
default:
break;
}
}
gboolean
gdk_color_parse (const gchar *spec,
GdkColor *color)
{
char aline[512];
FILE *fh;
g_return_val_if_fail(spec, FALSE);
g_return_val_if_fail(color, FALSE);
if(spec[0] == '#')
{
if(strlen(spec) == 7)
{
guint num;
sscanf(spec + 1, "%x", &num);
color->red = (num & 0xFF0000) >> 8;
color->green = (num & 0xFF00);
color->blue = (num & 0xFF) << 8;
}
else if(strlen(spec) == 13)
{
char s1[5], s2[5], s3[5];
g_snprintf(s1, sizeof(s1), spec + 1);
g_snprintf(s2, sizeof(s2), spec + 5);
g_snprintf(s3, sizeof(s3), spec + 9);
if(!sscanf(s1, "%hx", &color->red))
g_error("sscanf failed");
if(!sscanf(s2, "%hx", &color->green))
g_error("sscanf failed");
if(!sscanf(s3, "%hx", &color->blue))
g_error("sscanf failed");
}
else
{
g_warning("Couldn't parse color specifier `%s'", spec);
return FALSE;
}
return TRUE;
}
else
{
fh = fopen("/usr/lib/X11/rgb.txt", "r");
if(!fh)
return FALSE;
while(fgets(aline, sizeof(aline), fh))
{
int red, green, blue;
char *ctmp;
g_strstrip(aline);
if(!aline[0] || aline[0] == '#' || aline[0] == '!')
continue;
ctmp = strtok(aline, " \t");
if(!ctmp)
continue;
red = atoi(ctmp);
ctmp = strtok(NULL, " \t");
if(!ctmp)
continue;
green = atoi(ctmp);
ctmp = strtok(NULL, " \t");
if(!ctmp)
continue;
blue = atoi(ctmp);
ctmp = strtok(NULL, " \t");
if(!ctmp || strcmp(ctmp, spec))
continue;
color->red = red << 8;
color->green = green << 8;
color->blue = blue << 8;
return TRUE;
}
fclose(fh);
}
return FALSE;
}
void
gdk_colormap_free_colors (GdkColormap *colormap,
GdkColor *colors,
gint ncolors)
{
GdkColormapPrivateFB *private;
gint i;
g_return_if_fail (colormap != NULL);
g_return_if_fail (colors != NULL);
private = (GdkColormapPrivateFB*) colormap;
if ((private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
(private->base.visual->type != GDK_VISUAL_GRAYSCALE))
return;
for (i=0; i<ncolors; i++)
{
gulong pixel = colors[i].pixel;
if (private->info[pixel].ref_count)
{
private->info[pixel].ref_count--;
if (private->info[pixel].ref_count == 0)
{
if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
g_hash_table_remove (private->hash, &colormap->colors[pixel]);
private->info[pixel].flags = 0;
}
}
}
}
/********************
* Color allocation *
********************/
/* Try to allocate a single color using XAllocColor. If it succeeds,
* cache the result in our colormap, and store in ret.
*/
static gboolean
gdk_colormap_alloc1 (GdkColormap *colormap,
GdkColor *color,
GdkColor *ret)
{
GdkColormapPrivateFB *private;
int i;
private = (GdkColormapPrivateFB*) colormap;
if(private->base.visual->type != GDK_VISUAL_GRAYSCALE
&& private->base.visual->type != GDK_VISUAL_PSEUDO_COLOR)
return FALSE;
*ret = *color;
if(!color->red && !color->green && !color->blue) /* black */
{
ret->pixel = 0;
private->info[ret->pixel].ref_count++;
return TRUE;
}
if(color->red == 65535 && color->green == 65535 && color->blue == 65535) /* white */
{
ret->pixel = 255;
private->info[ret->pixel].ref_count++;
return TRUE;
}
for(i = 1; i < (colormap->size - 1); i++)
{
if(!private->info[i].ref_count)
{
guint16 red = color->red, green = color->green, blue = color->blue;
struct fb_cmap fbc;
fbc.len = 1;
fbc.start = i;
fbc.red = &red;
fbc.green = &green;
fbc.blue = &blue;
ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
ret->pixel = i;
colormap->colors[ret->pixel] = *ret;
private->info[ret->pixel].ref_count = 1;
g_hash_table_insert (private->hash,
&colormap->colors[ret->pixel],
&colormap->colors[ret->pixel]);
return TRUE;
}
}
return FALSE;
}
static gint
gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
GdkColor *colors,
gint ncolors,
gboolean writeable,
gboolean best_match,
gboolean *success)
{
GdkColormapPrivateFB *private;
gint i, index;
gint nremaining = 0;
gint nfailed = 0;
private = (GdkColormapPrivateFB*) colormap;
index = -1;
for (i=0; i<ncolors; i++)
{
if (!success[i])
{
if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
success[i] = TRUE;
else
nremaining++;
}
}
if (nremaining > 0 && best_match)
{
gchar *available = g_new (gchar, colormap->size);
for (i = 0; i < colormap->size; i++)
available[i] = ((private->info[i].ref_count == 0) ||
!(private->info[i].flags && GDK_COLOR_WRITEABLE));
while (nremaining > 0)
{
for (i=0; i<ncolors; i++)
{
if (!success[i])
{
index = gdk_colormap_match_color (colormap, &colors[i], available);
if (index != -1)
{
if (private->info[index].ref_count)
{
private->info[index].ref_count++;
colors[i] = colormap->colors[index];
success[i] = TRUE;
nremaining--;
}
else
{
if (gdk_colormap_alloc1 (colormap,
&colormap->colors[index],
&colors[i]))
{
success[i] = TRUE;
nremaining--;
break;
}
else
{
available[index] = FALSE;
}
}
}
else
{
nfailed++;
nremaining--;
success[i] = 2; /* flag as permanent failure */
}
}
}
}
g_free (available);
}
/* Change back the values we flagged as permanent failures */
if (nfailed > 0)
{
for (i=0; i<ncolors; i++)
if (success[i] == 2)
success[i] = FALSE;
nremaining = nfailed;
}
return (ncolors - nremaining);
}
static gint
gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
GdkColor *colors,
gint ncolors,
gboolean writeable,
gboolean best_match,
gboolean *success)
{
GdkColormapPrivateFB *private;
GdkColor *lookup_color;
gint i;
gint nremaining = 0;
private = (GdkColormapPrivateFB*) colormap;
/* Check for an exact match among previously allocated colors */
for (i=0; i<ncolors; i++)
{
if (!success[i])
{
lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
if (lookup_color)
{
private->info[lookup_color->pixel].ref_count++;
colors[i].pixel = lookup_color->pixel;
success[i] = TRUE;
}
else
nremaining++;
}
}
/* If that failed, we try to allocate a new color, or approxmiate
* with what we can get if best_match is TRUE.
*/
if (nremaining > 0)
return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
else
return 0;
}
gint
gdk_colormap_alloc_colors (GdkColormap *colormap,
GdkColor *colors,
gint ncolors,
gboolean writeable,
gboolean best_match,
gboolean *success)
{
GdkColormapPrivateFB *private;
GdkVisual *visual;
gint i;
gint nremaining = 0;
g_return_val_if_fail (colormap != NULL, FALSE);
g_return_val_if_fail (colors != NULL, FALSE);
private = (GdkColormapPrivateFB*) colormap;
for (i=0; i<ncolors; i++)
success[i] = FALSE;
switch (private->base.visual->type)
{
case GDK_VISUAL_PSEUDO_COLOR:
case GDK_VISUAL_GRAYSCALE:
case GDK_VISUAL_STATIC_GRAY:
case GDK_VISUAL_STATIC_COLOR:
return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
writeable, best_match, success);
break;
case GDK_VISUAL_DIRECT_COLOR:
case GDK_VISUAL_TRUE_COLOR:
visual = private->base.visual;
for (i=0; i<ncolors; i++)
{
colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
success[i] = TRUE;
}
break;
}
return nremaining;
}
gboolean
gdk_color_change (GdkColormap *colormap,
GdkColor *color)
{
GdkColormapPrivateFB *private;
struct fb_cmap fbc = {0, 1};
g_return_val_if_fail (colormap != NULL, FALSE);
g_return_val_if_fail (color != NULL, FALSE);
private = (GdkColormapPrivateFB*) colormap;
switch(private->base.visual->type)
{
case GDK_VISUAL_GRAYSCALE:
color->red = color->green = color->blue = (color->red + color->green + color->blue)/3;
case GDK_VISUAL_PSEUDO_COLOR:
fbc.start = color->pixel;
fbc.red = &color->red;
fbc.green = &color->green;
fbc.blue = &color->blue;
ioctl(gdk_display->fd, FBIOPUTCMAP, &fbc);
break;
default:
break;
}
return TRUE;
}
static gint
gdk_colormap_match_color (GdkColormap *cmap,
GdkColor *color,
const gchar *available)
{
GdkColor *colors;
guint sum, max;
gint rdiff, gdiff, bdiff;
gint i, index;
g_return_val_if_fail (cmap != NULL, 0);
g_return_val_if_fail (color != NULL, 0);
colors = cmap->colors;
max = 3 * (65536);
index = -1;
for (i = 0; i < cmap->size; i++)
{
if ((!available) || (available && available[i]))
{
rdiff = (color->red - colors[i].red);
gdiff = (color->green - colors[i].green);
bdiff = (color->blue - colors[i].blue);
sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
if (sum < max)
{
index = i;
max = sum;
}
}
}
return index;
}
gint gdk_colors_alloc (GdkColormap *colormap,
gboolean contiguous,
gulong *planes,
gint nplanes,
gulong *pixels,
gint npixels)
{
return 0;
}
void
gdk_colors_free (GdkColormap *colormap,
gulong *pixels,
gint npixels,
gulong planes)
{
}
gulong
gdk_color_context_get_pixel(GdkColorContext *cc,
gushort red,
gushort green,
gushort blue,
gint *failed)
{
g_error("NYI");
return 0;
}
GdkColorContext *
gdk_color_context_new(GdkVisual *visual,
GdkColormap *colormap)
{
g_error("NYI");
return NULL;
}
GdkColorContext *
gdk_color_context_new_mono(GdkVisual *visual,
GdkColormap *colormap)
{
g_error("NYI");
return NULL;
}
void
gdk_color_context_free(GdkColorContext *cc)
{
g_error("NYI");
}
gint
gdk_color_context_query_color(GdkColorContext *cc,
GdkColor *color)
{
g_error("NYI");
return 0;
}

View File

@ -0,0 +1,81 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "gdkfb.h"
#include "gdkprivate-fb.h"
#include "gdkcursor.h"
GdkCursor*
gdk_cursor_new (GdkCursorType cursor_type)
{
GdkCursorPrivateFB *private;
GdkCursor *cursor;
return NULL;
private = g_new0(GdkCursorPrivateFB, 1);
cursor = (GdkCursor*) private;
cursor->type = cursor_type;
cursor->ref_count = 1;
return cursor;
}
GdkCursor*
gdk_cursor_new_from_pixmap (GdkPixmap *source,
GdkPixmap *mask,
GdkColor *fg,
GdkColor *bg,
gint x,
gint y)
{
GdkCursorPrivateFB *private;
GdkCursor *cursor;
g_return_val_if_fail (source != NULL, NULL);
private = g_new (GdkCursorPrivateFB, 1);
cursor = (GdkCursor *) private;
cursor->type = GDK_CURSOR_IS_PIXMAP;
cursor->ref_count = 1;
private->cursor = gdk_pixmap_ref(source);
private->mask = gdk_pixmap_ref(mask);
return cursor;
}
void
_gdk_cursor_destroy (GdkCursor *cursor)
{
GdkCursorPrivateFB *private;
g_return_if_fail (cursor != NULL);
g_return_if_fail (cursor->ref_count == 0);
private = (GdkCursorPrivateFB *) cursor;
g_free (private);
}

264
gdk/linux-fb/gdkdnd-fb.c Normal file
View File

@ -0,0 +1,264 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <string.h>
#include "gdk.h" /* For gdk_flush() */
#include "gdkdnd.h"
#include "gdkproperty.h"
#include "gdkinternals.h"
#include "gdkprivate-fb.h"
typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
typedef enum {
GDK_DRAG_STATUS_DRAG,
GDK_DRAG_STATUS_MOTION_WAIT,
GDK_DRAG_STATUS_ACTION_WAIT,
GDK_DRAG_STATUS_DROP
} GtkDragStatus;
/* Structure that holds information about a drag in progress.
* this is used on both source and destination sides.
*/
struct _GdkDragContextPrivate {
GdkDragContext context;
guint ref_count;
};
/* Drag Contexts */
static GList *contexts;
GdkDragContext *
gdk_drag_context_new (void)
{
GdkDragContextPrivate *result;
result = g_new0 (GdkDragContextPrivate, 1);
result->ref_count = 1;
contexts = g_list_prepend (contexts, result);
return (GdkDragContext *)result;
}
void
gdk_drag_context_ref (GdkDragContext *context)
{
g_return_if_fail (context != NULL);
((GdkDragContextPrivate *)context)->ref_count++;
}
void
gdk_drag_context_unref (GdkDragContext *context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
g_return_if_fail (context != NULL);
g_return_if_fail (private->ref_count > 0);
private->ref_count--;
if (private->ref_count == 0)
{
g_dataset_destroy (private);
g_list_free (context->targets);
if (context->source_window)
{
#if 0
if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
!context->is_source)
xdnd_manage_source_filter (context, context->source_window, FALSE);
#endif
gdk_window_unref (context->source_window);
}
if (context->dest_window)
gdk_window_unref (context->dest_window);
#if 0
if (private->window_cache)
gdk_window_cache_destroy (private->window_cache);
#endif
contexts = g_list_remove (contexts, private);
g_free (private);
}
}
/*************************************************************
************************** Public API ***********************
*************************************************************/
void
gdk_dnd_init (void)
{
}
/* Source side */
static void
gdk_drag_do_leave (GdkDragContext *context, guint32 time) G_GNUC_UNUSED;
static void
gdk_drag_do_leave (GdkDragContext *context, guint32 time)
{
}
GdkDragContext *
gdk_drag_begin (GdkWindow *window,
GList *targets)
{
GList *tmp_list;
GdkDragContext *new_context;
g_return_val_if_fail (window != NULL, NULL);
new_context = gdk_drag_context_new ();
new_context->is_source = TRUE;
new_context->source_window = window;
gdk_window_ref (window);
tmp_list = g_list_last (targets);
new_context->targets = NULL;
while (tmp_list)
{
new_context->targets = g_list_prepend (new_context->targets,
tmp_list->data);
tmp_list = tmp_list->prev;
}
new_context->actions = 0;
return new_context;
}
guint32
gdk_drag_get_protocol (guint32 xid,
GdkDragProtocol *protocol)
{
*protocol = GDK_DRAG_PROTO_NONE;
return GDK_NONE;
}
void
gdk_drag_find_window (GdkDragContext *context,
GdkWindow *drag_window,
gint x_root,
gint y_root,
GdkWindow **dest_window,
GdkDragProtocol *protocol)
{
g_return_if_fail (context != NULL);
*dest_window = gdk_window_get_pointer(NULL, &x_root, &y_root, NULL);
}
gboolean
gdk_drag_motion (GdkDragContext *context,
GdkWindow *dest_window,
GdkDragProtocol protocol,
gint x_root,
gint y_root,
GdkDragAction suggested_action,
GdkDragAction possible_actions,
guint32 time)
{
g_return_val_if_fail (context != NULL, FALSE);
return FALSE;
}
void
gdk_drag_drop (GdkDragContext *context,
guint32 time)
{
g_return_if_fail (context != NULL);
}
void
gdk_drag_abort (GdkDragContext *context,
guint32 time)
{
g_return_if_fail (context != NULL);
}
/* Destination side */
void
gdk_drag_status (GdkDragContext *context,
GdkDragAction action,
guint32 time)
{
g_return_if_fail (context != NULL);
}
void
gdk_drop_reply (GdkDragContext *context,
gboolean ok,
guint32 time)
{
g_return_if_fail (context != NULL);
}
void
gdk_drop_finish (GdkDragContext *context,
gboolean success,
guint32 time)
{
g_return_if_fail (context != NULL);
}
void
gdk_window_register_dnd (GdkWindow *window)
{
g_return_if_fail (window != NULL);
}
/*************************************************************
* gdk_drag_get_selection:
* Returns the selection atom for the current source window
* arguments:
*
* results:
*************************************************************/
GdkAtom
gdk_drag_get_selection (GdkDragContext *context)
{
g_return_val_if_fail (context != NULL, GDK_NONE);
return GDK_NONE;
}

View File

@ -0,0 +1,959 @@
#include "gdkprivate-fb.h"
#include "mi.h"
#include <t1lib.h>
#ifndef g_alloca
#define g_alloca alloca
#endif
static void gdk_fb_drawable_destroy (GdkDrawable *drawable);
void gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
static void gdk_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2);
static void gdk_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints);
static void gdk_fb_draw_text (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length);
static void gdk_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length);
void gdk_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static void gdk_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
static void gdk_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs);
static void gdk_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
GdkDrawableClass _gdk_fb_drawable_class = {
gdk_fb_drawable_destroy,
(gpointer)_gdk_fb_gc_new,
gdk_fb_draw_rectangle,
gdk_fb_draw_arc,
gdk_fb_draw_polygon,
gdk_fb_draw_text,
gdk_fb_draw_text_wc,
gdk_fb_draw_drawable,
gdk_fb_draw_points,
gdk_fb_draw_segments,
gdk_fb_draw_lines
};
/*****************************************************
* FB specific implementations of generic functions *
*****************************************************/
GdkColormap*
gdk_drawable_get_colormap (GdkDrawable *drawable)
{
GdkColormap *retval = GDK_DRAWABLE_P(drawable)->colormap;
if(!retval)
retval = gdk_colormap_get_system();
return retval;
}
void
gdk_drawable_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap)
{
GdkColormap *old_cmap;
old_cmap = GDK_DRAWABLE_P(drawable)->colormap;
GDK_DRAWABLE_P(drawable)->colormap = gdk_colormap_ref(colormap);
gdk_colormap_unref(old_cmap);
}
/* Drawing
*/
static void
gdk_fb_drawable_destroy (GdkDrawable *drawable)
{
}
static GdkRegion *
gdk_fb_clip_region(GdkDrawable *drawable, GdkGC *gc, gboolean do_clipping)
{
GdkRectangle draw_rect;
GdkRegion *real_clip_region, *tmpreg;
g_assert(!GDK_IS_WINDOW(drawable) || !GDK_WINDOW_P(drawable)->input_only);
draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->llim_x;
draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->llim_y;
draw_rect.width = GDK_DRAWABLE_FBDATA(drawable)->lim_x - draw_rect.x;
draw_rect.height = GDK_DRAWABLE_FBDATA(drawable)->lim_y - draw_rect.y;
real_clip_region = gdk_region_rectangle(&draw_rect);
if(do_clipping && GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->mapped && !GDK_WINDOW_P(drawable)->input_only)
{
GdkWindow *parentwin, *lastwin;
for(parentwin = lastwin = ((GdkWindow *)drawable);
parentwin; lastwin = parentwin, parentwin = GDK_WINDOW_P(parentwin)->parent)
{
GList *cur;
for(cur = GDK_WINDOW_P(parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
{
if(!GDK_WINDOW_P(cur->data)->mapped || GDK_WINDOW_P(cur->data)->input_only)
continue;
draw_rect.x = GDK_DRAWABLE_FBDATA(cur->data)->llim_x;
draw_rect.y = GDK_DRAWABLE_FBDATA(cur->data)->llim_y;
draw_rect.width = GDK_DRAWABLE_FBDATA(cur->data)->lim_x - draw_rect.x;
draw_rect.height = GDK_DRAWABLE_FBDATA(cur->data)->lim_y - draw_rect.y;
tmpreg = gdk_region_rectangle(&draw_rect);
gdk_region_subtract(real_clip_region, tmpreg);
gdk_region_destroy(tmpreg);
}
}
}
if(gc)
{
if(GDK_GC_FBDATA(gc)->clip_region)
{
tmpreg = gdk_region_copy(GDK_GC_FBDATA(gc)->clip_region);
gdk_region_offset(tmpreg, GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_GC_P(gc)->clip_x_origin,
GDK_DRAWABLE_FBDATA(drawable)->abs_y + GDK_GC_P(gc)->clip_y_origin);
gdk_region_intersect(real_clip_region, tmpreg);
gdk_region_destroy(tmpreg);
}
if(GDK_GC_FBDATA(gc)->values.clip_mask)
{
GdkDrawable *cmask = GDK_GC_FBDATA(gc)->values.clip_mask;
g_assert(GDK_DRAWABLE_P(cmask)->depth == 1);
g_assert(GDK_DRAWABLE_FBDATA(cmask)->abs_x == 0
&& GDK_DRAWABLE_FBDATA(cmask)->abs_y == 0);
draw_rect.x = GDK_DRAWABLE_FBDATA(drawable)->abs_x + GDK_DRAWABLE_FBDATA(cmask)->llim_x + GDK_GC_FBDATA(gc)->values.clip_x_origin;
draw_rect.y = GDK_DRAWABLE_FBDATA(drawable)->abs_y + GDK_DRAWABLE_FBDATA(cmask)->llim_y + GDK_GC_FBDATA(gc)->values.clip_y_origin;
draw_rect.width = GDK_DRAWABLE_P(cmask)->width;
draw_rect.height = GDK_DRAWABLE_P(cmask)->height;
tmpreg = gdk_region_rectangle(&draw_rect);
gdk_region_intersect(real_clip_region, tmpreg);
gdk_region_destroy(tmpreg);
}
}
return real_clip_region;
}
static void
gdk_fb_fill_span(GdkDrawable *drawable, GdkGC *gc, GdkSegment *cur, guint pixel, GdkVisual *visual)
{
int curx, cury;
guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem;
guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride;
guint depth = GDK_DRAWABLE_P(drawable)->depth;
if(gc
&& (GDK_GC_FBDATA(gc)->values.clip_mask
|| GDK_GC_FBDATA(gc)->values.tile
|| GDK_GC_FBDATA(gc)->values.stipple))
{
int clipxoff, clipyoff; /* Amounts to add to curx & cury to get x & y in clip mask */
int tsxoff, tsyoff;
GdkDrawable *cmask;
guchar *clipmem;
guint mask_rowstride;
GdkPixmap *ts = NULL;
gboolean solid_stipple;
cmask = GDK_GC_FBDATA(gc)->values.clip_mask;
if(cmask)
{
clipmem = GDK_DRAWABLE_FBDATA(cmask)->mem;
clipxoff = GDK_DRAWABLE_FBDATA(cmask)->abs_x - GDK_GC_FBDATA(gc)->values.clip_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
clipyoff = GDK_DRAWABLE_FBDATA(cmask)->abs_y - GDK_GC_FBDATA(gc)->values.clip_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
mask_rowstride = GDK_DRAWABLE_FBDATA(cmask)->rowstride;
}
if(GDK_GC_FBDATA(gc)->values.fill == GDK_TILED
&& GDK_GC_FBDATA(gc)->values.tile)
{
gint xstep, ystep;
gint relx, rely;
ts = GDK_GC_FBDATA(gc)->values.tile;
for(cury = cur->y1; cury < cur->y2; cury += ystep)
{
int drawh;
rely = cury - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
drawh = (rely + GDK_GC_FBDATA(gc)->values.ts_y_origin) % GDK_DRAWABLE_P(ts)->height;
if(drawh < 0)
drawh += GDK_DRAWABLE_P(ts)->height;
ystep = MIN(GDK_DRAWABLE_P(ts)->height - drawh, cur->y2 - rely);
for(curx = cur->x1; curx < cur->x2; curx += xstep)
{
int draww;
relx = curx - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
draww = (relx + GDK_GC_FBDATA(gc)->values.ts_x_origin) % GDK_DRAWABLE_P(ts)->width;
if(draww < 0)
draww += GDK_DRAWABLE_P(ts)->width;
xstep = MIN(GDK_DRAWABLE_P(ts)->width - draww, cur->x2 - relx);
gdk_fb_draw_drawable_2(drawable, gc, ts,
draww, drawh,
relx, rely,
xstep, ystep, FALSE, TRUE);
}
}
return;
}
else if((GDK_GC_FBDATA(gc)->values.fill == GDK_STIPPLED
|| GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED)
&& GDK_GC_FBDATA(gc)->values.stipple)
{
ts = GDK_GC_FBDATA(gc)->values.stipple;
tsxoff = GDK_DRAWABLE_FBDATA(ts)->abs_x - GDK_GC_FBDATA(gc)->values.ts_x_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
tsyoff = GDK_DRAWABLE_FBDATA(ts)->abs_y - GDK_GC_FBDATA(gc)->values.ts_y_origin - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
solid_stipple = (GDK_GC_FBDATA(gc)->values.fill == GDK_OPAQUE_STIPPLED);
}
switch(depth)
{
case 1:
g_assert(!ts);
for(cury = cur->y1; cury < cur->y2; cury++)
{
for(curx = cur->x1; curx < cur->x2; curx++)
{
guchar *ptr = mem + (cury * rowstride) + (curx >> 3);
int maskx = curx+clipxoff, masky = cury + clipyoff;
guchar foo;
if(cmask)
{
foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
if(!(foo & (1 << (maskx % 8))))
continue;
}
*ptr |= (1 << (curx % 8));
}
}
break;
case 8:
for(cury = cur->y1; cury < cur->y2; cury++)
{
for(curx = cur->x1; curx < cur->x2; curx++)
{
guchar *ptr = mem + (cury * rowstride) + curx;
int maskx = curx+clipxoff, masky = cury + clipyoff;
guchar foo;
if(cmask)
{
foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
if(!(foo & (1 << (maskx % 8))))
continue;
}
if(ts)
{
int wid = GDK_DRAWABLE_P(ts)->width, hih = GDK_DRAWABLE_P(ts)->height;
maskx = (curx+tsxoff)%wid;
masky = (cury+tsyoff)%hih;
if(maskx < 0)
maskx += wid;
if(masky < 0)
masky += hih;
foo = GDK_DRAWABLE_FBDATA(ts)->mem[(maskx >> 3) + GDK_DRAWABLE_FBDATA(ts)->rowstride*masky];
if(foo & (1 << (maskx % 8)))
{
pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
}
else if(solid_stipple)
{
pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
}
else
continue;
}
*ptr = pixel;
}
}
break;
case 16:
case 24:
case 32:
for(cury = cur->y1; cury < cur->y2; cury++)
{
for(curx = cur->x1; curx < cur->x2; curx++)
{
guint *ptr2 = (guint *)(mem + (cury * rowstride) + (curx * (depth >> 3)));
int maskx = curx+clipxoff, masky = cury + clipyoff;
guchar foo;
if(cmask)
{
foo = clipmem[masky*mask_rowstride + (maskx >> 3)];
if(!(foo & (1 << (maskx % 8))))
continue;
}
if(ts)
{
int wid = GDK_DRAWABLE_P(ts)->width, hih = GDK_DRAWABLE_P(ts)->height;
maskx = (curx+tsxoff)%wid;
masky = (cury+tsyoff)%hih;
if(maskx < 0)
maskx += wid;
if(masky < 0)
masky += hih;
foo = GDK_DRAWABLE_FBDATA(ts)->mem[(maskx >> 3) + GDK_DRAWABLE_FBDATA(ts)->rowstride*masky];
if(foo & (1 << (maskx % 8)))
{
pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
}
else if(solid_stipple)
{
pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
}
else
continue;
}
*ptr2 = (*ptr2 & ~(visual->red_mask|visual->green_mask|visual->blue_mask)) | pixel;
}
}
break;
}
}
else
{
switch(depth)
{
case 1:
for(cury = cur->y1; cury < cur->y2; cury++)
{
for(curx = cur->x1; curx < cur->x2; curx++)
{
guchar *ptr = mem + (cury * rowstride) + (curx >> 3);
if(pixel)
*ptr |= (1 << (curx % 8));
else
*ptr &= ~(1 << (curx % 8));
}
}
break;
case 8:
for(cury = cur->y1; cury < cur->y2; cury++)
{
guchar *ptr = mem + (cury * rowstride) + cur->x1;
memset(ptr, pixel, cur->x2 - cur->x1);
}
break;
case 16:
case 24:
case 32:
for(cury = cur->y1; cury < cur->y2; cury++)
{
for(curx = cur->x1; curx < cur->x2; curx++)
{
guint *ptr2 = (guint *)(mem + (cury * rowstride) + (curx * (depth >> 3)));
*ptr2 = (*ptr2 & ~(visual->red_mask|visual->green_mask|visual->blue_mask)) | pixel;
}
}
break;
}
}
}
void
gdk_fb_fill_spans(GdkDrawable *drawable,
GdkGC *gc,
GdkRectangle *rects, int nrects)
{
int i;
guint pixel;
GdkRegion *real_clip_region, *tmpreg;
GdkRectangle draw_rect, cursor_rect;
GdkVisual *visual = gdk_visual_get_system();
gboolean handle_cursor = FALSE;
if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
return;
if(GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->input_only)
g_error("Drawing on the evil input-only!");
if(gc)
pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
else if(GDK_IS_WINDOW(drawable))
pixel = GDK_WINDOW_P(drawable)->bg_color.pixel;
else
pixel = 0;
real_clip_region = gdk_fb_clip_region(drawable, gc, TRUE);
gdk_fb_get_cursor_rect(&cursor_rect);
if(GDK_DRAWABLE_FBDATA(drawable)->mem == GDK_DRAWABLE_FBDATA(gdk_parent_root)->mem
&& cursor_rect.x >= 0
&& gdk_region_rect_in(real_clip_region, &cursor_rect) != GDK_OVERLAP_RECTANGLE_OUT)
{
handle_cursor = TRUE;
gdk_fb_cursor_hide();
}
for(i = 0; i < nrects; i++)
{
GdkSegment cur;
int j;
cur.x1 = rects[i].x;
cur.y1 = rects[i].y;
cur.x2 = cur.x1 + rects[i].width;
cur.y2 = cur.y1 + rects[i].height;
g_assert(cur.x2 >= cur.x1);
g_assert(cur.y2 >= cur.y1);
cur.x1 += GDK_DRAWABLE_FBDATA(drawable)->abs_x;
cur.x1 = MAX(cur.x1, GDK_DRAWABLE_FBDATA(drawable)->llim_x);
cur.x2 += GDK_DRAWABLE_FBDATA(drawable)->abs_x;
cur.x2 = MIN(cur.x2, GDK_DRAWABLE_FBDATA(drawable)->lim_x);
cur.x1 = MIN(cur.x1, cur.x2);
cur.y1 += GDK_DRAWABLE_FBDATA(drawable)->abs_y;
cur.y1 = MAX(cur.y1, GDK_DRAWABLE_FBDATA(drawable)->llim_y);
cur.y2 += GDK_DRAWABLE_FBDATA(drawable)->abs_y;
cur.y2 = MIN(cur.y2, GDK_DRAWABLE_FBDATA(drawable)->lim_y);
cur.y1 = MIN(cur.y1, cur.y2);
draw_rect.x = cur.x1;
draw_rect.y = cur.y1;
draw_rect.width = cur.x2 - cur.x1;
draw_rect.height = cur.y2 - cur.y1;
switch(gdk_region_rect_in(real_clip_region, &draw_rect))
{
case GDK_OVERLAP_RECTANGLE_PART:
tmpreg = gdk_region_rectangle(&draw_rect);
gdk_region_intersect(tmpreg, real_clip_region);
for(j = 0; j < tmpreg->numRects; j++)
gdk_fb_fill_span(drawable, gc, &tmpreg->rects[j], pixel, visual);
gdk_region_destroy(tmpreg);
break;
case GDK_OVERLAP_RECTANGLE_IN:
gdk_fb_fill_span(drawable, gc, &cur, pixel, visual);
break;
default:
break;
}
}
gdk_region_destroy(real_clip_region);
if(handle_cursor)
gdk_fb_cursor_unhide();
}
void
gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height,
gboolean draw_bg,
gboolean do_clipping)
{
GdkRegion *real_clip_region, *tmpreg;
GdkRectangle rect, cursor_rect;
int i;
int src_x_off, src_y_off;
int clipxoff, clipyoff;
guchar *mem = GDK_DRAWABLE_FBDATA(drawable)->mem, *srcmem = GDK_DRAWABLE_FBDATA(src)->mem;
guchar *clipmem;
guint rowstride = GDK_DRAWABLE_FBDATA(drawable)->rowstride, src_rowstride = GDK_DRAWABLE_FBDATA(src)->rowstride;
guint clip_rowstride;
GdkDrawableFBData *fbd;
gboolean handle_cursor = FALSE;
GdkPixmap *bgpm = NULL;
GdkWindow *bg_relto = drawable;
if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
return;
if(GDK_IS_WINDOW(drawable) && GDK_WINDOW_P(drawable)->input_only)
g_error("Drawing on the evil input-only!");
if(GDK_IS_WINDOW(drawable))
{
bgpm = GDK_WINDOW_P(drawable)->bg_pixmap;
if(bgpm == GDK_PARENT_RELATIVE_BG)
{
for(; bgpm == GDK_PARENT_RELATIVE_BG && bg_relto; bg_relto = GDK_WINDOW_P(bg_relto)->parent)
bgpm = GDK_WINDOW_P(bg_relto)->bg_pixmap;
}
if(bgpm == GDK_NO_BG)
bgpm = NULL;
if(bgpm)
g_assert(GDK_DRAWABLE_P(bgpm)->depth == 8);
}
if(drawable == src)
{
GdkDrawableFBData *fbd = GDK_DRAWABLE_FBDATA(src);
/* One lame hack deserves another ;-) */
srcmem = g_alloca(fbd->rowstride * fbd->lim_y);
memcpy(srcmem, mem, fbd->rowstride * fbd->lim_y);
}
real_clip_region = gdk_fb_clip_region(drawable, gc, do_clipping);
rect.x = xdest + GDK_DRAWABLE_FBDATA(drawable)->abs_x;
rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->abs_y;
rect.width = width;
rect.height = height;
tmpreg = gdk_region_rectangle(&rect);
gdk_region_intersect(real_clip_region, tmpreg);
gdk_region_destroy(tmpreg);
rect.x = xdest + GDK_DRAWABLE_FBDATA(drawable)->abs_x;
rect.y = ydest + GDK_DRAWABLE_FBDATA(drawable)->abs_y;
rect.width = MAX(GDK_DRAWABLE_P(src)->width - xsrc, 0);
rect.height = MAX(GDK_DRAWABLE_P(src)->height - ysrc, 0);
if(!rect.width || !rect.height)
goto out;
tmpreg = gdk_region_rectangle(&rect);
gdk_region_intersect(real_clip_region, tmpreg);
gdk_region_destroy(tmpreg);
src_x_off = (GDK_DRAWABLE_FBDATA(src)->abs_x + xsrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_x + xdest);
src_y_off = (GDK_DRAWABLE_FBDATA(src)->abs_y + ysrc) - (GDK_DRAWABLE_FBDATA(drawable)->abs_y + ydest);
clipxoff = - GDK_DRAWABLE_FBDATA(drawable)->abs_x;
clipyoff = - GDK_DRAWABLE_FBDATA(drawable)->abs_y;
if(gc)
{
clipxoff -= GDK_GC_FBDATA(gc)->values.clip_x_origin;
clipyoff -= GDK_GC_FBDATA(gc)->values.clip_y_origin;
if(GDK_GC_FBDATA(gc)->values.clip_mask)
{
fbd = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask);
clipmem = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask)->mem;
clip_rowstride = GDK_DRAWABLE_FBDATA(GDK_GC_FBDATA(gc)->values.clip_mask)->rowstride;
}
}
gdk_fb_get_cursor_rect(&cursor_rect);
if(do_clipping
&& GDK_DRAWABLE_FBDATA(drawable)->mem == GDK_DRAWABLE_FBDATA(gdk_parent_root)->mem
&& cursor_rect.x >= 0
&& gdk_region_rect_in(real_clip_region, &cursor_rect) != GDK_OVERLAP_RECTANGLE_OUT)
{
handle_cursor = TRUE;
gdk_fb_cursor_hide();
}
for(i = 0; i < real_clip_region->numRects; i++)
{
GdkRegionBox *cur = &real_clip_region->rects[i];
int cur_y;
if(GDK_DRAWABLE_P(src)->depth == GDK_DRAWABLE_P(drawable)->depth
&& GDK_DRAWABLE_P(src)->depth > 1
&& (!gc || !GDK_GC_FBDATA(gc)->values.clip_mask))
{
guint depth = GDK_DRAWABLE_P(src)->depth;
for(cur_y = cur->y1; cur_y < cur->y2; cur_y++)
{
memcpy(mem + (cur_y * rowstride) + cur->x1*(depth>>3),
srcmem + ((cur_y + src_y_off)*src_rowstride) + (cur->x1 + src_x_off)*(depth>>3),
(cur->x2 - cur->x1)*(depth>>3));
}
}
else
{
int cur_x;
for(cur_y = cur->y1; cur_y < cur->y2; cur_y++)
{
for(cur_x = cur->x1; cur_x < cur->x2; cur_x++)
{
guint pixel;
guint16 *p16;
guint32 *p32;
if(gc && GDK_GC_FBDATA(gc)->values.clip_mask)
{
int maskx = cur_x+clipxoff, masky = cur_y + clipyoff;
guchar foo;
if(maskx < 0 || masky < 0)
continue;
foo = clipmem[masky*clip_rowstride + (maskx >> 3)];
if(!(foo & (1 << (maskx % 8))))
continue;
}
switch(GDK_DRAWABLE_P(src)->depth)
{
case 1:
{
guchar foo = srcmem[((cur_x + src_x_off) >> 3) + ((cur_y + src_y_off)*src_rowstride)];
if(foo & (1 << ((cur_x + src_x_off) % 8))) {
pixel = GDK_GC_FBDATA(gc)->values.foreground.pixel;
} else if(draw_bg) {
if(bgpm)
{
int bgx, bgy;
bgx = (cur_x - GDK_DRAWABLE_FBDATA(bg_relto)->abs_x) % GDK_DRAWABLE_P(bgpm)->width;
bgy = (cur_y - GDK_DRAWABLE_FBDATA(bg_relto)->abs_y) % GDK_DRAWABLE_P(bgpm)->height;
pixel = GDK_DRAWABLE_FBDATA(bgpm)->mem[bgx + bgy * GDK_DRAWABLE_FBDATA(bgpm)->rowstride];
}
else
pixel = GDK_GC_FBDATA(gc)->values.background.pixel;
} else
continue;
}
break;
case 8:
pixel = srcmem[(cur_x + src_x_off) + ((cur_y + src_y_off)*src_rowstride)];
break;
case 16:
pixel = *(guint16 *)(srcmem + (cur_x + src_x_off)*2 + ((cur_y + src_y_off)*src_rowstride));
break;
case 24:
pixel = 0x00FFFFFF & *(guint32 *)(srcmem + (cur_x + src_x_off)*3 + ((cur_y + src_y_off)*src_rowstride));
break;
case 32:
pixel = *(guint32 *)(srcmem + (cur_x + src_x_off)*4 + ((cur_y + src_y_off)*src_rowstride));
break;
default:
g_assert_not_reached();
break;
}
switch(GDK_DRAWABLE_P(drawable)->depth)
{
case 1:
{
guchar *foo = mem + (cur_y*src_rowstride) + (cur_x >> 3);
if(pixel == GDK_GC_FBDATA(gc)->values.foreground.pixel)
*foo |= (1 << (cur_x % 8));
else
*foo &= ~(1 << (cur_x % 8));
}
break;
case 8:
mem[cur_x + cur_y*rowstride] = pixel;
break;
case 16:
p16 = (guint16 *)&mem[cur_x*2 + cur_y*rowstride];
*p16 = pixel;
break;
case 24:
p32 = (guint32 *)&mem[cur_x*3 + cur_y*rowstride];
*p32 = (*p32 & 0xFF000000) | pixel;
break;
case 32:
p32 = (guint32 *)&mem[cur_x*4 + cur_y*rowstride];
*p32 = pixel;
break;
default:
g_assert_not_reached();
break;
}
}
}
}
}
out:
gdk_region_destroy(real_clip_region);
if(handle_cursor)
gdk_fb_cursor_unhide();
}
void
gdk_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
gdk_fb_draw_drawable_2(drawable, gc, src, xsrc, ysrc, xdest, ydest, width, height, TRUE, TRUE);
}
static void
gdk_fb_draw_text(GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const gchar *text,
gint text_length)
{
GLYPH *g;
GdkDrawablePrivate tmp_pixmap;
GdkDrawableFBData fbd;
if(GDK_IS_WINDOW(drawable) && !GDK_WINDOW_P(drawable)->mapped)
return;
y -= font->ascent; /* y is relative to baseline, we want it relative to top left corner */
g = T1_SetString(GDK_FONT_FB(font)->t1_font_id, (char *)text, text_length, 0, T1_KERNING, GDK_FONT_FB(font)->size,
NULL);
g_assert(g);
tmp_pixmap.window_type = GDK_DRAWABLE_PIXMAP;
tmp_pixmap.width = (g->metrics.rightSideBearing - g->metrics.leftSideBearing);
tmp_pixmap.height = (g->metrics.ascent - g->metrics.descent);
tmp_pixmap.depth = 1;
fbd.mem = g->bits;
fbd.abs_x = fbd.abs_y = fbd.llim_x = fbd.llim_y = 0;
fbd.lim_x = tmp_pixmap.width;
fbd.lim_y = tmp_pixmap.height;
fbd.rowstride = (tmp_pixmap.width + 7) / 8;
tmp_pixmap.klass_data = &fbd;
tmp_pixmap.klass = &_gdk_fb_drawable_class;
gdk_fb_draw_drawable_2(drawable, gc, (GdkPixmap *)&tmp_pixmap, 0, 0, x, y, tmp_pixmap.width, tmp_pixmap.height, FALSE, TRUE);
}
static void
gdk_fb_draw_text_wc (GdkDrawable *drawable,
GdkFont *font,
GdkGC *gc,
gint x,
gint y,
const GdkWChar *text,
gint text_length)
{
char *realbuf;
int i;
if(GDK_IS_WINDOW(drawable) && (!GDK_WINDOW_P(drawable)->mapped || GDK_WINDOW_P(drawable)->input_only))
return;
/* A hack, a hack, a pretty little hack */
realbuf = alloca(text_length + 1);
for(i = 0; i < text_length; i++)
realbuf[i] = text[i];
realbuf[i] = 0;
gdk_fb_draw_text(drawable, font, gc, x, y, realbuf, text_length);
}
void
gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height)
{
GdkRectangle rect;
if(filled)
{
static volatile int print_rect = 0;
if(print_rect)
{
fprintf(debug_out, "[%d, %d] +[%d, %d]\n", x, y, width, height);
if(y < 0)
G_BREAKPOINT();
}
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
gdk_fb_fill_spans(drawable, gc, &rect, 1);
}
else
{
GdkPoint pts[5];
pts[0].x = pts[4].x = x;
pts[0].y = pts[4].y = y;
pts[1].x = x + width;
pts[1].y = y;
pts[2].x = x + width;
pts[2].y = y + height;
pts[3].x = x;
pts[3].y = y + height;
gdk_fb_draw_lines(drawable, gc, pts, 5);
}
}
static void gdk_fb_draw_points (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
GdkRectangle *rects = alloca(npoints * sizeof(GdkRectangle));
int i;
for(i = 0; i < npoints; i++)
{
rects[i].x = points[i].x;
rects[i].y = points[i].y;
rects[i].width = rects[i].height = 1;
}
gdk_fb_fill_spans(drawable, gc, rects, npoints);
}
static void gdk_fb_draw_arc (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height,
gint angle1,
gint angle2)
{
miArc arc;
arc.x = x;
arc.y = y;
arc.width = width;
arc.height = height;
arc.angle1 = angle1;
arc.angle2 = angle2;
if(filled)
miPolyFillArc(drawable, gc, 1, &arc);
else
miPolyArc(drawable, gc, 1, &arc);
}
static void gdk_fb_draw_polygon (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
GdkPoint *points,
gint npoints)
{
if(filled)
miFillPolygon(drawable, gc, 0, 0, npoints, points);
else
{
GdkPoint *realpts = alloca(sizeof(GdkPoint) * (npoints + 1));
memcpy(realpts, points, sizeof(GdkPoint) * npoints);
realpts[npoints] = points[0];
gdk_fb_draw_lines(drawable, gc, points, npoints);
}
}
static void gdk_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints)
{
if(GDK_GC_FBDATA(gc)->values.line_width > 0)
miWideLine(drawable, gc, 0, npoints, points);
else
miZeroLine(drawable, gc, 0, npoints, points);
}
static void gdk_fb_draw_segments (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *segs,
gint nsegs)
{
GdkPoint pts[2];
int i;
for(i = 0; i < nsegs; i++)
{
pts[0].x = segs[i].x1;
pts[0].y = segs[i].y1;
pts[1].x = segs[i].x2;
pts[1].y = segs[i].y2;
gdk_fb_draw_lines(drawable, gc, pts, 2);
}
}
void
gdk_fb_drawable_clear(GdkDrawable *d)
{
_gdk_windowing_window_clear_area(d, 0, 0, GDK_DRAWABLE_P(d)->width, GDK_DRAWABLE_P(d)->height);
}

209
gdk/linux-fb/gdkevents-fb.c Normal file
View File

@ -0,0 +1,209 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "gdk.h"
#include "gdkprivate-fb.h"
#include "gdkinternals.h"
#include "gdkfb.h"
#include "gdkkeysyms.h"
#if HAVE_CONFIG_H
# include <config.h>
# if STDC_HEADERS
# include <string.h>
# endif
#endif
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
#define DOUBLE_CLICK_TIME 250
#define TRIPLE_CLICK_TIME 500
#define DOUBLE_CLICK_DIST 5
#define TRIPLE_CLICK_DIST 5
typedef enum
{
/* Following flag is set for events on the event queue during
* translation and cleared afterwards.
*/
GDK_EVENT_PENDING = 1 << 0
} GdkEventFlags;
struct _GdkIOClosure
{
GdkInputFunction function;
GdkInputCondition condition;
GdkDestroyNotify notify;
gpointer data;
};
struct _GdkEventPrivate
{
GdkEvent event;
guint flags;
};
/*
* Private function declarations
*/
/* Private variable declarations
*/
#if 0
static GList *client_filters; /* Filters for client messages */
static GSourceFuncs event_funcs = {
gdk_event_prepare,
gdk_event_check,
gdk_event_dispatch,
(GDestroyNotify)g_free
};
#endif
/*********************************************
* Functions for maintaining the event queue *
*********************************************/
void
gdk_events_init (void)
{
}
/*
*--------------------------------------------------------------
* gdk_events_pending
*
* Returns if events are pending on the queue.
*
* Arguments:
*
* Results:
* Returns TRUE if events are pending
*
* Side effects:
*
*--------------------------------------------------------------
*/
gboolean
gdk_events_pending (void)
{
return gdk_event_queue_find_first()?TRUE:FALSE;
}
GdkEvent*
gdk_event_get_graphics_expose (GdkWindow *window)
{
g_return_val_if_fail (window != NULL, NULL);
return NULL;
}
void
gdk_events_queue (void)
{
}
static gint handler_tag = 0;
static gboolean
dispatch_events(gpointer data)
{
GdkEvent *event;
GDK_THREADS_ENTER();
while((event = gdk_event_unqueue()))
{
if(event->type == GDK_EXPOSE
&& event->expose.window == gdk_parent_root)
gdk_fb_drawable_clear(event->expose.window);
else if(gdk_event_func)
(*gdk_event_func)(event, gdk_event_data);
gdk_event_free(event);
}
GDK_THREADS_LEAVE();
if(event && !handler_tag)
handler_tag = g_idle_add_full(G_PRIORITY_HIGH_IDLE, dispatch_events, NULL, NULL);
else if(!event && handler_tag)
{
g_source_remove(handler_tag);
handler_tag = 0;
}
return handler_tag?TRUE:FALSE;
}
void
_gdk_event_queue_changed(GList *queue)
{
if(queue && !handler_tag)
handler_tag = g_idle_add_full(G_PRIORITY_HIGH_IDLE, dispatch_events, NULL, NULL);
else if(!queue && handler_tag)
{
g_source_remove(handler_tag);
handler_tag = 0;
}
}
/*
*--------------------------------------------------------------
* gdk_flush
*
* Flushes the Xlib output buffer and then waits
* until all requests have been received and processed
* by the X server. The only real use for this function
* is in dealing with XShm.
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
void
gdk_flush (void)
{
}
gboolean
gdk_event_send_client_message (GdkEvent *event, guint32 xid)
{
return FALSE;
}
void gdk_event_send_clientmessage_toall (GdkEvent *sev)
{
}

18
gdk/linux-fb/gdkfb.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef GDKFB_H
#define GDKFB_H 1
#include "gdk/gdkprivate.h"
typedef struct _GdkFBDisplay GdkFBDisplay;
typedef struct _GdkFBWindow GdkFBWindow;
extern GdkFBWindow *gdk_root_window;
extern GdkFBDisplay *gdk_display;
#define GDK_ROOT_WINDOW() gdk_root_window
#define GDK_ROOT_PARENT() ((GdkWindow *)gdk_parent_root)
#define GDK_DISPLAY() gdk_display
extern const char *gdk_progclass;
#endif /* GDKFB_H */

328
gdk/linux-fb/gdkfont-fb.c Normal file
View File

@ -0,0 +1,328 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <t1lib.h>
#include <math.h>
#include <stdlib.h>
#include "gdkfont.h"
#include "gdkprivate-fb.h"
static GHashTable *font_name_hash = NULL;
static GHashTable *fontset_name_hash = NULL;
static void
gdk_font_hash_insert (GdkFontType type, GdkFont *font, const gchar *font_name)
{
GdkFontPrivateFB *private = (GdkFontPrivateFB *)font;
GHashTable **hashp = (type == GDK_FONT_FONT) ?
&font_name_hash : &fontset_name_hash;
if (!*hashp)
*hashp = g_hash_table_new (g_str_hash, g_str_equal);
private->names = g_slist_prepend (private->names, g_strdup (font_name));
g_hash_table_insert (*hashp, private->names->data, font);
}
static void
gdk_font_hash_remove (GdkFontType type, GdkFont *font)
{
GdkFontPrivateFB *private = (GdkFontPrivateFB *)font;
GSList *tmp_list;
GHashTable *hash = (type == GDK_FONT_FONT) ?
font_name_hash : fontset_name_hash;
tmp_list = private->names;
while (tmp_list)
{
g_hash_table_remove (hash, tmp_list->data);
g_free (tmp_list->data);
tmp_list = tmp_list->next;
}
g_slist_free (private->names);
private->names = NULL;
}
static GdkFont *
gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
{
GdkFont *result;
GHashTable *hash = (type == GDK_FONT_FONT) ?
font_name_hash : fontset_name_hash;
if (!hash)
return NULL;
else
{
result = g_hash_table_lookup (hash, font_name);
if (result)
gdk_font_ref (result);
return result;
}
}
GdkFont*
gdk_font_load (const gchar *font_name)
{
GdkFont *font;
GdkFontPrivateFB *private;
g_return_val_if_fail (font_name != NULL, NULL);
font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
if (font)
return font;
{
char **pieces;
BBox bb;
private = g_new0 (GdkFontPrivateFB, 1);
private->base.ref_count = 1;
private->names = NULL;
pieces = g_strsplit(font_name, "-", 2);
if(pieces[1])
{
private->size = atof(pieces[1]);
private->t1_font_id = T1_AddFont(pieces[0]);
}
else
private->t1_font_id = T1_AddFont((char *)font_name);
g_strfreev(pieces);
T1_LoadFont(private->t1_font_id);
CreateNewFontSize(private->t1_font_id, private->size, FALSE);
font = (GdkFont*) private;
font->type = GDK_FONT_FONTSET;
bb = T1_GetFontBBox(private->t1_font_id);
font->ascent = ((double)bb.ury) / 1000.0 * private->size;
font->descent = ((double)bb.lly) / -1000.0 * private->size;
}
gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
return font;
}
GdkFont*
gdk_fontset_load (const gchar *fontset_name)
{
return gdk_font_load(fontset_name);
}
void
_gdk_font_destroy (GdkFont *font)
{
gdk_font_hash_remove (font->type, font);
switch (font->type)
{
case GDK_FONT_FONT:
break;
case GDK_FONT_FONTSET:
break;
default:
g_error ("unknown font type.");
break;
}
g_free (font);
}
gint
_gdk_font_strlen (GdkFont *font,
const gchar *str)
{
GdkFontPrivateFB *font_private;
gint length = 0;
g_return_val_if_fail (font != NULL, -1);
g_return_val_if_fail (str != NULL, -1);
font_private = (GdkFontPrivateFB*) font;
if (font->type == GDK_FONT_FONT)
{
guint16 *string_2b = (guint16 *)str;
while (*(string_2b++))
length++;
}
else if (font->type == GDK_FONT_FONTSET)
{
length = strlen (str);
}
else
g_error("undefined font type\n");
return length;
}
gint
gdk_font_id (const GdkFont *font)
{
const GdkFontPrivateFB *font_private;
g_return_val_if_fail (font != NULL, 0);
font_private = (const GdkFontPrivateFB*) font;
if (font->type == GDK_FONT_FONT)
{
return -1;
}
else
{
return 0;
}
}
gint
gdk_font_equal (const GdkFont *fonta,
const GdkFont *fontb)
{
const GdkFontPrivateFB *privatea;
const GdkFontPrivateFB *privateb;
g_return_val_if_fail (fonta != NULL, FALSE);
g_return_val_if_fail (fontb != NULL, FALSE);
privatea = (const GdkFontPrivateFB*) fonta;
privateb = (const GdkFontPrivateFB*) fontb;
if(fonta == fontb)
return TRUE;
if(privatea->t1_font_id == privateb->t1_font_id
&& privatea->size == privateb->size)
return TRUE;
return FALSE;
}
gint
gdk_text_width (GdkFont *font,
const gchar *text,
gint text_length)
{
GdkFontPrivateFB *private;
gint width;
double n;
g_return_val_if_fail (font != NULL, -1);
g_return_val_if_fail (text != NULL, -1);
private = (GdkFontPrivateFB*) font;
switch (font->type)
{
case GDK_FONT_FONT:
case GDK_FONT_FONTSET:
n = private->size / 1000.0;
n *= T1_GetStringWidth(private->t1_font_id, (char *)text, text_length, 0, T1_KERNING);
width = ceil(n);
break;
default:
width = 0;
break;
}
return width;
}
gint
gdk_text_width_wc (GdkFont *font,
const GdkWChar *text,
gint text_length)
{
char *realstr;
int i;
realstr = alloca(text_length + 1);
for(i = 0; i < text_length; i++)
realstr[i] = text[i];
realstr[i] = '\0';
return gdk_text_width(font, realstr, text_length);
}
void
gdk_text_extents (GdkFont *font,
const gchar *text,
gint text_length,
gint *lbearing,
gint *rbearing,
gint *width,
gint *ascent,
gint *descent)
{
GdkFontPrivateFB *private;
METRICSINFO mi;
g_return_if_fail (font != NULL);
g_return_if_fail (text != NULL);
private = (GdkFontPrivateFB*) font;
mi = T1_GetMetricsInfo(private->t1_font_id, (char *)text, text_length, 0, T1_KERNING);
if(ascent)
*ascent = ((double)mi.bbox.ury) / 1000.0 * private->size;
if(descent)
*descent = ((double)mi.bbox.lly) / -1000.0 * private->size;
if(width)
*width = ((double)mi.width) / 1000.0 * private->size;
if(lbearing)
*lbearing = ((double)mi.bbox.llx) / 1000.0 * private->size;
if(rbearing)
*rbearing = ((double)mi.bbox.urx) / 1000.0 * private->size;
}
void
gdk_text_extents_wc (GdkFont *font,
const GdkWChar *text,
gint text_length,
gint *lbearing,
gint *rbearing,
gint *width,
gint *ascent,
gint *descent)
{
char *realstr;
int i;
realstr = alloca(text_length + 1);
for(i = 0; i < text_length; i++)
realstr[i] = text[i];
realstr[i] = '\0';
return gdk_text_extents(font, realstr, text_length, lbearing, rbearing, width, ascent, descent);
}

308
gdk/linux-fb/gdkgc-fb.c Normal file
View File

@ -0,0 +1,308 @@
#include "gdkprivate-fb.h"
#include "gdkgc.h"
#include "gdkfb.h"
#include "gdkregion-generic.h"
typedef enum {
GDK_GC_DIRTY_CLIP = 1 << 0,
GDK_GC_DIRTY_TS = 1 << 1
} GdkGCDirtyValues;
static void gdk_fb_gc_destroy (GdkGC *gc);
static void gdk_fb_gc_get_values (GdkGC *gc,
GdkGCValues *values);
static void gdk_fb_gc_set_values (GdkGC *gc,
GdkGCValues *values,
GdkGCValuesMask values_mask);
static void gdk_fb_gc_set_dashes (GdkGC *gc,
gint dash_offset,
gchar dash_list[],
gint n);
static GdkGCClass gdk_fb_gc_class = {
gdk_fb_gc_destroy,
gdk_fb_gc_get_values,
gdk_fb_gc_set_values,
gdk_fb_gc_set_dashes
};
GdkGC *
_gdk_fb_gc_new (GdkDrawable *drawable,
GdkGCValues *values,
GdkGCValuesMask values_mask)
{
GdkGC *gc;
GdkGCPrivate *private;
GdkGCFBData *data;
gc = gdk_gc_alloc ();
private = (GdkGCPrivate *)gc;
private->klass = &gdk_fb_gc_class;
private->klass_data = data = g_new0 (GdkGCFBData, 1);
data->values.foreground.pixel = 255;
data->values.foreground.red = data->values.foreground.green = data->values.foreground.blue = 65535;
gdk_fb_gc_set_values(gc, values, values_mask);
return gc;
}
static void
gdk_fb_gc_destroy (GdkGC *gc)
{
if (GDK_GC_FBDATA (gc)->clip_region)
gdk_region_destroy (GDK_GC_FBDATA (gc)->clip_region);
g_free (GDK_GC_FBDATA (gc));
}
static void
gdk_fb_gc_get_values (GdkGC *gc,
GdkGCValues *values)
{
*values = GDK_GC_FBDATA(gc)->values;
}
static void
gdk_fb_gc_set_values (GdkGC *gc,
GdkGCValues *values,
GdkGCValuesMask values_mask)
{
GdkPixmap *oldpm;
GdkFont *oldf;
if(values_mask & GDK_GC_FOREGROUND)
{
GDK_GC_FBDATA(gc)->values.foreground = values->foreground;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FOREGROUND;
}
if(values_mask & GDK_GC_BACKGROUND)
{
GDK_GC_FBDATA(gc)->values.background = values->background;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_BACKGROUND;
}
if(values_mask & GDK_GC_FONT)
{
oldf = GDK_GC_FBDATA(gc)->values.font;
GDK_GC_FBDATA(gc)->values.font = gdk_font_ref(values->font);
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FONT;
if(oldf)
gdk_font_unref(oldf);
}
if(values_mask & GDK_GC_FUNCTION)
{
GDK_GC_FBDATA(gc)->values.function = values->function;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FUNCTION;
}
if(values_mask & GDK_GC_FILL)
{
GDK_GC_FBDATA(gc)->values.fill = values->fill;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_FILL;
}
if(values_mask & GDK_GC_TILE)
{
oldpm = GDK_GC_FBDATA(gc)->values.tile;
if(values->tile)
g_assert(GDK_DRAWABLE_P(values->tile)->depth == 8);
GDK_GC_FBDATA(gc)->values.tile = values->tile?gdk_pixmap_ref(values->tile):NULL;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TILE;
if(oldpm)
gdk_pixmap_unref(oldpm);
}
if(values_mask & GDK_GC_STIPPLE)
{
oldpm = GDK_GC_FBDATA(gc)->values.stipple;
if(values->stipple)
g_assert(GDK_DRAWABLE_P(values->stipple)->depth == 1);
GDK_GC_FBDATA(gc)->values.stipple = values->stipple?gdk_pixmap_ref(values->stipple):NULL;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_STIPPLE;
if(oldpm)
gdk_pixmap_unref(oldpm);
}
if(values_mask & GDK_GC_CLIP_MASK)
{
oldpm = GDK_GC_FBDATA(gc)->values.clip_mask;
GDK_GC_FBDATA(gc)->values.clip_mask = values->clip_mask?gdk_pixmap_ref(values->clip_mask):NULL;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_MASK;
if(oldpm)
gdk_pixmap_unref(oldpm);
}
if(values_mask & GDK_GC_SUBWINDOW)
{
GDK_GC_FBDATA(gc)->values.subwindow_mode = values->subwindow_mode;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_SUBWINDOW;
}
if(values_mask & GDK_GC_TS_X_ORIGIN)
{
GDK_GC_FBDATA(gc)->values.ts_x_origin = values->ts_x_origin;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TS_X_ORIGIN;
}
if(values_mask & GDK_GC_TS_Y_ORIGIN)
{
GDK_GC_FBDATA(gc)->values.ts_y_origin = values->ts_y_origin;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_TS_Y_ORIGIN;
}
if(values_mask & GDK_GC_CLIP_X_ORIGIN)
{
GDK_GC_FBDATA(gc)->values.clip_x_origin = GDK_GC_P(gc)->clip_x_origin = values->clip_x_origin;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_X_ORIGIN;
}
if(values_mask & GDK_GC_CLIP_Y_ORIGIN)
{
GDK_GC_FBDATA(gc)->values.clip_y_origin = GDK_GC_P(gc)->clip_y_origin = values->clip_y_origin;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CLIP_Y_ORIGIN;
}
if(values_mask & GDK_GC_EXPOSURES)
{
GDK_GC_FBDATA(gc)->values.graphics_exposures = values->graphics_exposures;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_EXPOSURES;
}
if(values_mask & GDK_GC_LINE_WIDTH)
{
GDK_GC_FBDATA(gc)->values.line_width = values->line_width;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_LINE_WIDTH;
}
if(values_mask & GDK_GC_LINE_STYLE)
{
GDK_GC_FBDATA(gc)->values.line_style = values->line_style;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_LINE_STYLE;
}
if(values_mask & GDK_GC_CAP_STYLE)
{
GDK_GC_FBDATA(gc)->values.cap_style = values->cap_style;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_CAP_STYLE;
}
if(values_mask & GDK_GC_JOIN_STYLE)
{
GDK_GC_FBDATA(gc)->values.join_style = values->join_style;
GDK_GC_FBDATA(gc)->values_mask |= GDK_GC_JOIN_STYLE;
}
}
static void
gdk_fb_gc_set_dashes (GdkGC *gc,
gint dash_offset,
gchar dash_list[],
gint n)
{
GDK_GC_FBDATA(gc)->dash_offset = dash_offset;
GDK_GC_FBDATA(gc)->dash_list_len = n;
if(n)
{
GDK_GC_FBDATA(gc)->dash_list = g_realloc(GDK_GC_FBDATA(gc)->dash_list, n);
memcpy(GDK_GC_FBDATA(gc)->dash_list, dash_list, n);
}
else
{
g_free(GDK_GC_FBDATA(gc)->dash_list);
GDK_GC_FBDATA(gc)->dash_list = NULL;
}
}
void
gdk_gc_set_clip_rectangle (GdkGC *gc,
GdkRectangle *rectangle)
{
GdkGCPrivate *private = (GdkGCPrivate *)gc;
GdkGCFBData *data;
g_return_if_fail (gc != NULL);
data = GDK_GC_FBDATA (gc);
if (data->clip_region)
{
gdk_region_destroy (data->clip_region);
data->clip_region = NULL;
}
if (rectangle)
data->clip_region = gdk_region_rectangle (rectangle);
private->clip_x_origin = 0;
private->clip_y_origin = 0;
data->values.clip_x_origin = 0;
data->values.clip_y_origin = 0;
}
void
gdk_gc_set_clip_region (GdkGC *gc,
GdkRegion *region)
{
GdkGCPrivate *private = (GdkGCPrivate *)gc;
GdkGCFBData *data;
g_return_if_fail (gc != NULL);
data = GDK_GC_FBDATA (gc);
if(region == data->clip_region)
return;
if (data->clip_region)
{
gdk_region_destroy (data->clip_region);
data->clip_region = NULL;
}
if (region)
data->clip_region = gdk_region_copy (region);
private->clip_x_origin = 0;
private->clip_y_origin = 0;
data->values.clip_x_origin = 0;
data->values.clip_y_origin = 0;
}
void
gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
{
g_return_if_fail (dst_gc != NULL);
g_return_if_fail (src_gc != NULL);
if(GDK_GC_FBDATA(dst_gc)->clip_region)
gdk_region_destroy(GDK_GC_FBDATA(dst_gc)->clip_region);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_FONT)
gdk_font_unref(GDK_GC_FBDATA(dst_gc)->values.font);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_TILE)
gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.tile);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_STIPPLE)
gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.stipple);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_CLIP_MASK)
gdk_pixmap_unref(GDK_GC_FBDATA(dst_gc)->values.clip_mask);
*dst_gc = *src_gc;
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_FONT)
gdk_font_ref(GDK_GC_FBDATA(dst_gc)->values.font);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_TILE)
gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.tile);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_STIPPLE)
gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.stipple);
if(GDK_GC_FBDATA(dst_gc)->values_mask & GDK_GC_CLIP_MASK)
gdk_pixmap_ref(GDK_GC_FBDATA(dst_gc)->values.clip_mask);
if(GDK_GC_FBDATA(dst_gc)->clip_region)
GDK_GC_FBDATA(dst_gc)->clip_region = gdk_region_copy(GDK_GC_FBDATA(dst_gc)->clip_region);
}

View File

View File

@ -0,0 +1,41 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <stdio.h>
#include "gdktypes.h"
#include "gdkprivate-fb.h"
#include "config.h"
const gchar *gdk_progclass = "none";
gboolean gdk_null_window_warnings = TRUE;
GdkWindow *_gdk_fb_pointer_grab_window, *_gdk_fb_keyboard_grab_window, *_gdk_fb_pointer_grab_confine = NULL;
GdkEventMask _gdk_fb_pointer_grab_events, _gdk_fb_keyboard_grab_events;
GdkFBWindow *gdk_root_window = NULL;
GdkFBDisplay *gdk_display = NULL;
GdkCursor *_gdk_fb_pointer_grab_cursor;

242
gdk/linux-fb/gdkim-fb.c Normal file
View File

@ -0,0 +1,242 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "gdki18n.h"
#include "gdkinternals.h"
#include "gdkprivate-fb.h"
#if HAVE_CONFIG_H
# include <config.h>
# if STDC_HEADERS
# include <string.h>
# endif
#endif
#include <locale.h>
/* If this variable is FALSE, it indicates that we should
* avoid trying to use multibyte conversion functions and
* assume everything is 1-byte per character
*/
static gboolean gdk_use_mb;
/*
*--------------------------------------------------------------
* gdk_set_locale
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gchar*
gdk_set_locale (void)
{
wchar_t result;
gchar *current_locale;
gdk_use_mb = FALSE;
if (!setlocale (LC_ALL,""))
g_warning ("locale not supported by C library");
current_locale = setlocale (LC_ALL, NULL);
if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
{
gdk_use_mb = TRUE;
#ifndef X_LOCALE
/* Detect GNU libc, where mb == UTF8. Not useful unless it's
* really a UTF8 locale. The below still probably will
* screw up on Greek, Cyrillic, etc, encoded as UTF8.
*/
if ((MB_CUR_MAX == 2) &&
(mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
result == 0x765)
{
if ((strlen (current_locale) < 4) ||
g_strcasecmp (current_locale + strlen(current_locale) - 4, "utf8"))
gdk_use_mb = FALSE;
}
#endif /* X_LOCALE */
}
GDK_NOTE (MISC,
g_message ("%s multi-byte string functions.",
gdk_use_mb ? "Using" : "Not using"));
return current_locale;
}
void
gdk_im_begin (GdkIC *ic, GdkWindow* window)
{
}
void
gdk_im_end (void)
{
}
GdkIMStyle
gdk_im_decide_style (GdkIMStyle supported_style)
{
return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
}
GdkIMStyle
gdk_im_set_best_style (GdkIMStyle style)
{
return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
}
gint
gdk_im_ready (void)
{
return FALSE;
}
gint
gdk_im_open(void)
{
return TRUE;
}
void
gdk_im_close(void)
{
}
GdkIC *
gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
{
return NULL;
}
void
gdk_ic_destroy (GdkIC *ic)
{
}
GdkIMStyle
gdk_ic_get_style (GdkIC *ic)
{
return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
}
void
gdk_ic_set_values (GdkIC *ic, ...)
{
}
void
gdk_ic_get_values (GdkIC *ic, ...)
{
}
GdkICAttributesType
gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
{
return 0;
}
GdkICAttributesType
gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
{
return 0;
}
GdkEventMask
gdk_ic_get_events (GdkIC *ic)
{
return 0;
}
/*
* gdk_wcstombs
*
* Returns a multi-byte string converted from the specified array
* of wide characters. The string is newly allocated. The array of
* wide characters must be null-terminated. If the conversion is
* failed, it returns NULL.
*/
gchar *
gdk_wcstombs (const GdkWChar *src)
{
gchar *mbstr;
gint length = 0;
gint i;
while (src[length] != 0)
length++;
mbstr = g_new (gchar, length + 1);
for (i=0; i<length+1; i++)
mbstr[i] = src[i];
return mbstr;
}
/*
* gdk_mbstowcs
*
* Converts the specified string into wide characters, and, returns the
* number of wide characters written. The string 'src' must be
* null-terminated. If the conversion is failed, it returns -1.
*/
gint
gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
{
gint i;
for (i=0; i<dest_max && src[i]; i++)
dest[i] = src[i];
return i;
}
void
gdk_ic_cleanup(void)
{
}
GdkICAttr* gdk_ic_attr_new (void)
{
return NULL;
}
void
gdk_ic_attr_destroy (GdkICAttr *attr)
{
}

268
gdk/linux-fb/gdkimage-fb.c Normal file
View File

@ -0,0 +1,268 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <config.h>
#include <stdlib.h>
#include <sys/types.h>
#include "gdk.h"
#include "gdkimage.h"
#include "gdkprivate.h"
#include "gdkprivate-fb.h"
struct _GdkImagePrivateFB
{
GdkImagePrivate base;
};
static void gdk_fb_image_destroy (GdkImage *image);
static void gdk_image_put_normal (GdkImage *image,
GdkDrawable *drawable,
GdkGC *gc,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
static GdkImageClass image_class_normal = {
gdk_fb_image_destroy,
gdk_image_put_normal
};
GdkImage *
gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h)
{
GdkImage *image;
GdkImagePrivateFB *private;
private = g_new(GdkImagePrivateFB, 1);
image = (GdkImage *) private;
private->base.ref_count = 1;
private->base.klass = &image_class_normal;
image->type = GDK_IMAGE_NORMAL;
image->visual = visual;
image->width = w;
image->height = h;
image->depth = 1;
image->byte_order = 1 /* MSBFirst */;
image->mem = g_malloc(w * h / 8);
image->bpp = 1;
image->bpl = (w+7)/8;
return image;
}
void
gdk_image_init (void)
{
}
GdkImage*
gdk_image_new (GdkImageType type,
GdkVisual *visual,
gint width,
gint height)
{
GdkImage *image;
GdkImagePrivateFB *private;
private = g_new (GdkImagePrivateFB, 1);
image = (GdkImage*) private;
private->base.ref_count = 1;
image->type = 0;
image->visual = visual;
image->width = width;
image->height = height;
image->depth = visual->depth;
private->base.klass = &image_class_normal;
if (image)
{
image->byte_order = 0;
image->mem = g_malloc(width * height * (image->depth >> 3));
image->bpp = image->depth;
image->bpl = (width * image->depth + 7)/8;
}
return image;
}
GdkImage*
gdk_image_get (GdkWindow *window,
gint x,
gint y,
gint width,
gint height)
{
GdkImage *image;
GdkImagePrivateFB *private;
gint bits_per_pixel = GDK_DRAWABLE_P(gdk_parent_root)->depth;
GdkDrawableFBData fbd;
GdkDrawablePrivate tmp_foo;
g_return_val_if_fail (window != NULL, NULL);
if (GDK_DRAWABLE_DESTROYED (window))
return NULL;
private = g_new (GdkImagePrivateFB, 1);
image = (GdkImage*) private;
private->base.ref_count = 1;
private->base.klass = &image_class_normal;
image->type = GDK_IMAGE_NORMAL;
image->visual = gdk_window_get_visual (window);
image->width = width;
image->height = height;
image->depth = bits_per_pixel;
if (bits_per_pixel <= 8)
image->bpp = 1;
else if (bits_per_pixel <= 16)
image->bpp = 2;
else if (bits_per_pixel <= 24)
image->bpp = 3;
else
image->bpp = 4;
image->byte_order = 1;
image->bpl = (image->width * image->bpp + 7)/8;
image->mem = g_malloc(image->bpl * image->height);
/* Fake its existence as a pixmap */
memset(&tmp_foo, 0, sizeof(tmp_foo));
memset(&fbd, 0, sizeof(fbd));
tmp_foo.klass = &_gdk_fb_drawable_class;
tmp_foo.klass_data = &fbd;
fbd.mem = image->mem;
fbd.rowstride = image->bpl;
tmp_foo.width = fbd.lim_x = image->width;
tmp_foo.height = fbd.lim_y = image->height;
tmp_foo.depth = image->depth;
gdk_fb_draw_drawable((GdkPixmap *)&tmp_foo, NULL, window, x, y, 0, 0, width, height);
return image;
}
guint32
gdk_image_get_pixel (GdkImage *image,
gint x,
gint y)
{
GdkImagePrivateFB *private;
g_return_val_if_fail (image != NULL, 0);
private = (GdkImagePrivateFB *) image;
g_assert(image->depth == 8);
return ((guchar *)image->mem)[x + y * image->bpl];
}
void
gdk_image_put_pixel (GdkImage *image,
gint x,
gint y,
guint32 pixel)
{
GdkImagePrivateFB *private;
g_return_if_fail (image != NULL);
private = (GdkImagePrivateFB *) image;
g_assert(image->depth == 8);
((guchar *)image->mem)[x + y * image->bpl] = pixel;
}
static void
gdk_fb_image_destroy (GdkImage *image)
{
GdkImagePrivateFB *private;
g_return_if_fail (image != NULL);
private = (GdkImagePrivateFB*) image;
g_free(image->mem); image->mem = NULL;
g_free (image);
}
static void
gdk_image_put_normal (GdkImage *image,
GdkDrawable *drawable,
GdkGC *gc,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height)
{
GdkImagePrivateFB *image_private;
GdkDrawableFBData fbd;
GdkDrawablePrivate tmp_foo;
g_return_if_fail (drawable != NULL);
g_return_if_fail (image != NULL);
g_return_if_fail (gc != NULL);
if (GDK_DRAWABLE_DESTROYED (drawable))
return;
image_private = (GdkImagePrivateFB*) image;
g_return_if_fail (image->type == GDK_IMAGE_NORMAL);
/* Fake its existence as a pixmap */
memset(&tmp_foo, 0, sizeof(tmp_foo));
memset(&fbd, 0, sizeof(fbd));
tmp_foo.klass = &_gdk_fb_drawable_class;
tmp_foo.klass_data = &fbd;
fbd.mem = image->mem;
fbd.rowstride = image->bpl;
tmp_foo.width = fbd.lim_x = image->width;
tmp_foo.height = fbd.lim_y = image->height;
tmp_foo.depth = image->depth;
gdk_fb_draw_drawable(drawable, gc, (GdkPixmap *)&tmp_foo, xsrc, ysrc, xdest, ydest, width, height);
}
void
gdk_image_exit(void)
{
}

View File

@ -0,0 +1,79 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gdkinputprivate.h"
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
static void gdk_input_none_get_pointer (GdkWindow *window,
guint32 deviceid,
gdouble *x,
gdouble *y,
gdouble *pressure,
gdouble *xtilt,
gdouble *ytilt,
GdkModifierType *mask);
void
gdk_input_init (void)
{
gdk_input_vtable.set_mode = NULL;
gdk_input_vtable.set_axes = NULL;
gdk_input_vtable.set_key = NULL;
gdk_input_vtable.motion_events = NULL;
gdk_input_vtable.get_pointer = gdk_input_none_get_pointer;
gdk_input_vtable.grab_pointer = NULL;
gdk_input_vtable.ungrab_pointer = NULL;
gdk_input_vtable.configure_event = NULL;
gdk_input_vtable.enter_event = NULL;
gdk_input_vtable.other_event = NULL;
gdk_input_vtable.window_none_event = NULL;
gdk_input_vtable.enable_window = NULL;
gdk_input_vtable.disable_window = NULL;
gdk_input_devices = g_list_append (NULL, (GdkDeviceInfo *) &gdk_input_core_info);
gdk_input_ignore_core = FALSE;
}
static void
gdk_input_none_get_pointer (GdkWindow *window,
guint32 deviceid,
gdouble *x,
gdouble *y,
gdouble *pressure,
gdouble *xtilt,
gdouble *ytilt,
GdkModifierType *mask)
{
gint x_int, y_int;
gdk_window_get_pointer (window, &x_int, &y_int, mask);
if (x) *x = x_int;
if (y) *y = y_int;
if (pressure) *pressure = 0.5;
if (xtilt) *xtilt = 0;
if (ytilt) *ytilt = 0;
}

1096
gdk/linux-fb/gdkinput-ps2.c Normal file

File diff suppressed because it is too large Load Diff

290
gdk/linux-fb/gdkinput.c Normal file
View File

@ -0,0 +1,290 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <stdlib.h>
#include "config.h"
#include "gdkfb.h"
#include "gdkinput.h"
#include "gdkprivate.h"
#include "gdkinputprivate.h"
static const GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
const GdkDeviceInfo gdk_input_core_info =
{
GDK_CORE_POINTER,
"Core Pointer",
GDK_SOURCE_MOUSE,
GDK_MODE_SCREEN,
TRUE,
2,
gdk_input_core_axes
};
/* Global variables */
GdkInputVTable gdk_input_vtable;
/* information about network port and host for gxid daemon */
gchar *gdk_input_gxid_host;
gint gdk_input_gxid_port;
gint gdk_input_ignore_core;
GList *gdk_input_devices;
GList *gdk_input_windows;
GList *
gdk_input_list_devices (void)
{
return gdk_input_devices;
}
void
gdk_input_set_source (guint32 deviceid, GdkInputSource source)
{
GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid);
g_return_if_fail (gdkdev != NULL);
gdkdev->info.source = source;
}
gint
gdk_input_set_mode (guint32 deviceid, GdkInputMode mode)
{
if (deviceid == GDK_CORE_POINTER)
return FALSE;
if (gdk_input_vtable.set_mode)
return gdk_input_vtable.set_mode(deviceid,mode);
else
return FALSE;
}
void
gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes)
{
if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes)
gdk_input_vtable.set_axes (deviceid, axes);
}
void gdk_input_set_key (guint32 deviceid,
guint index,
guint keyval,
GdkModifierType modifiers)
{
if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
}
GdkTimeCoord *
gdk_input_motion_events (GdkWindow *window,
guint32 deviceid,
guint32 start,
guint32 stop,
gint *nevents_return)
{
g_return_val_if_fail (window != NULL, NULL);
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
*nevents_return = 0;
return NULL;
}
gint
gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
{
if (gdk_input_vtable.enable_window)
return gdk_input_vtable.enable_window (window, gdkdev);
else
return TRUE;
}
gint
gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev)
{
if (gdk_input_vtable.disable_window)
return gdk_input_vtable.disable_window(window,gdkdev);
else
return TRUE;
}
GdkInputWindow *
gdk_input_window_find(GdkWindow *window)
{
GList *tmp_list;
for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
if (((GdkInputWindow *)(tmp_list->data))->window == window)
return (GdkInputWindow *)(tmp_list->data);
return NULL; /* Not found */
}
/* FIXME: this routine currently needs to be called between creation
and the corresponding configure event (because it doesn't get the
root_relative_geometry). This should work with
gtk_window_set_extension_events, but will likely fail in other
cases */
void
gdk_input_set_extension_events (GdkWindow *window, gint mask,
GdkExtensionMode mode)
{
GdkWindowPrivate *window_private;
GList *tmp_list;
GdkInputWindow *iw;
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
window_private = (GdkWindowPrivate*) window;
if (GDK_DRAWABLE_DESTROYED (window))
return;
if (mode == GDK_EXTENSION_EVENTS_NONE)
mask = 0;
if (mask != 0)
{
iw = g_new(GdkInputWindow,1);
iw->window = window;
iw->mode = mode;
iw->obscuring = NULL;
iw->num_obscuring = 0;
iw->grabbed = FALSE;
gdk_input_windows = g_list_append(gdk_input_windows,iw);
window_private->extension_events = mask;
/* Add enter window events to the event mask */
/* FIXME, this is not needed for XINPUT_NONE */
gdk_window_set_events (window,
gdk_window_get_events (window) |
GDK_ENTER_NOTIFY_MASK);
}
else
{
iw = gdk_input_window_find (window);
if (iw)
{
gdk_input_windows = g_list_remove(gdk_input_windows,iw);
g_free(iw);
}
window_private->extension_events = 0;
}
for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
{
GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
if (gdkdev->info.deviceid != GDK_CORE_POINTER)
{
if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
&& (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
gdk_input_enable_window(window,gdkdev);
else
gdk_input_disable_window(window,gdkdev);
}
}
}
void
gdk_input_window_destroy (GdkWindow *window)
{
GdkInputWindow *input_window;
input_window = gdk_input_window_find (window);
g_return_if_fail (input_window != NULL);
gdk_input_windows = g_list_remove (gdk_input_windows,input_window);
g_free(input_window);
}
void
gdk_input_exit (void)
{
GList *tmp_list;
GdkDevicePrivate *gdkdev;
for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
{
gdkdev = (GdkDevicePrivate *)(tmp_list->data);
if (gdkdev->info.deviceid != GDK_CORE_POINTER)
{
gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED);
g_free(gdkdev->info.name);
#ifndef XINPUT_NONE
g_free(gdkdev->axes);
#endif
g_free(gdkdev->info.axes);
g_free(gdkdev->info.keys);
g_free(gdkdev);
}
}
g_list_free(gdk_input_devices);
for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
{
g_free(tmp_list->data);
}
g_list_free(gdk_input_windows);
}
GdkDevicePrivate *
gdk_input_find_device(guint32 id)
{
GList *tmp_list = gdk_input_devices;
GdkDevicePrivate *gdkdev;
while (tmp_list)
{
gdkdev = (GdkDevicePrivate *)(tmp_list->data);
if (gdkdev->info.deviceid == id)
return gdkdev;
tmp_list = tmp_list->next;
}
return NULL;
}
void
gdk_input_window_get_pointer (GdkWindow *window,
guint32 deviceid,
gdouble *x,
gdouble *y,
gdouble *pressure,
gdouble *xtilt,
gdouble *ytilt,
GdkModifierType *mask)
{
if (gdk_input_vtable.get_pointer)
gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
xtilt, ytilt, mask);
}

View File

@ -0,0 +1,222 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __GDK_INPUTPRIVATE_H__
#define __GDK_INPUTPRIVATE_H__
#include "config.h"
#include "gdkinput.h"
#include "gdkevents.h"
#include "gdkfb.h"
typedef struct _GdkAxisInfo GdkAxisInfo;
typedef struct _GdkInputVTable GdkInputVTable;
typedef struct _GdkDevicePrivate GdkDevicePrivate;
typedef struct _GdkInputWindow GdkInputWindow;
struct _GdkInputVTable {
gint (*set_mode) (guint32 deviceid, GdkInputMode mode);
void (*set_axes) (guint32 deviceid, GdkAxisUse *axes);
void (*set_key) (guint32 deviceid,
guint index,
guint keyval,
GdkModifierType modifiers);
GdkTimeCoord* (*motion_events) (GdkWindow *window,
guint32 deviceid,
guint32 start,
guint32 stop,
gint *nevents_return);
void (*get_pointer) (GdkWindow *window,
guint32 deviceid,
gdouble *x,
gdouble *y,
gdouble *pressure,
gdouble *xtilt,
gdouble *ytilt,
GdkModifierType *mask);
gint (*grab_pointer) (GdkWindow * window,
gint owner_events,
GdkEventMask event_mask,
GdkWindow * confine_to,
guint32 time);
void (*ungrab_pointer) (guint32 time);
void (*configure_event) (GdkEventConfigure *event, GdkWindow *window);
void (*enter_event) (GdkEventCrossing *event, GdkWindow *window);
gint (*other_event) (GdkEvent *event, GdkWindow *window);
/* Handle an unidentified event. Returns TRUE if handled, FALSE
otherwise */
gint (*window_none_event) (GdkEvent *event);
gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
};
/* information about a device axis */
struct _GdkAxisInfo
{
/* reported x resolution */
gint xresolution;
/* reported x minimum/maximum values */
gint xmin_value, xmax_value;
/* calibrated resolution (for aspect ration) - only relative values
between axes used */
gint resolution;
/* calibrated minimum/maximum values */
gint min_value, max_value;
};
#define GDK_INPUT_NUM_EVENTC 6
struct _GdkDevicePrivate {
GdkDeviceInfo info;
#ifndef XINPUT_NONE
/* information about the axes */
GdkAxisInfo *axes;
/* reverse lookup on axis use type */
gint axis_for_use[GDK_AXIS_LAST];
/* Information about XInput device */
XDevice *xdevice;
/* minimum key code for device */
gint min_keycode;
int buttonpress_type, buttonrelease_type, keypress_type,
keyrelease_type, motionnotify_type, proximityin_type,
proximityout_type, changenotify_type;
/* true if we need to select a different set of events, but
can't because this is the core pointer */
gint needs_update;
/* Mask of buttons (used for button grabs) */
gint button_state;
/* true if we've claimed the device as active. (used only for XINPUT_GXI) */
gint claimed;
#endif /* !XINPUT_NONE */
};
struct _GdkInputWindow
{
/* gdk window */
GdkWindow *window;
/* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */
GdkExtensionMode mode;
/* position relative to root window */
gint root_x;
gint root_y;
/* rectangles relative to window of windows obscuring this one */
GdkRectangle *obscuring;
gint num_obscuring;
/* Is there a pointer grab for this window ? */
gint grabbed;
};
/* Global data */
extern const GdkDeviceInfo gdk_input_core_info;
extern GList *gdk_input_devices;
extern GList *gdk_input_windows;
extern GdkInputVTable gdk_input_vtable;
/* information about network port and host for gxid daemon */
extern gchar *gdk_input_gxid_host;
extern gint gdk_input_gxid_port;
extern gint gdk_input_ignore_core;
/* Function declarations */
GdkDevicePrivate * gdk_input_find_device (guint32 id);
GdkInputWindow * gdk_input_window_find (GdkWindow *window);
void gdk_input_window_destroy (GdkWindow *window);
void gdk_input_init (void);
void gdk_input_exit (void);
gint gdk_input_enable_window (GdkWindow *window,
GdkDevicePrivate *gdkdev);
gint gdk_input_disable_window (GdkWindow *window,
GdkDevicePrivate *gdkdev);
#ifndef XINPUT_NONE
#define GDK_MAX_DEVICE_CLASSES 13
gint gdk_input_common_init (gint include_core);
void gdk_input_get_root_relative_geometry (Display *dpy,
Window w,
int *x_ret,
int *y_ret,
int *width_ret,
int *height_ret);
void gdk_input_common_find_events (GdkWindow *window,
GdkDevicePrivate *gdkdev,
gint mask,
XEventClass *classes,
int *num_classes);
void gdk_input_common_select_events (GdkWindow *window,
GdkDevicePrivate *gdkdev);
gint gdk_input_common_other_event (GdkEvent *event,
XEvent *xevent,
GdkInputWindow *input_window,
GdkDevicePrivate *gdkdev);
void gdk_input_common_get_pointer (GdkWindow *window,
guint32 deviceid,
gdouble *x,
gdouble *y,
gdouble *pressure,
gdouble *xtilt,
gdouble *ytilt,
GdkModifierType *mask);
void gdk_input_common_set_key (guint32 deviceid,
guint index,
guint keyval,
GdkModifierType modifiers);
void gdk_input_common_set_axes (guint32 deviceid,
GdkAxisUse *axes);
GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window,
guint32 deviceid,
guint32 start,
guint32 stop,
gint *nevents_return);
#endif /* !XINPUT_NONE */
GdkDevicePrivate *gdk_input_find_device (guint32 id);
GdkInputWindow *gdk_input_window_find (GdkWindow *window);
void gdk_input_window_destroy (GdkWindow *window);
void gdk_input_exit (void);
#endif /* __GDK_INPUTPRIVATE_H__ */

575
gdk/linux-fb/gdkmain-fb.c Normal file
View File

@ -0,0 +1,575 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <t1lib.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include "gdk.h"
#include "gdkprivate-fb.h"
#include "gdkinternals.h"
/*
* Private function declarations
*/
#ifndef HAVE_XCONVERTCASE
static void gdkx_XConvertCase (KeySym symbol,
KeySym *lower,
KeySym *upper);
#define XConvertCase gdkx_XConvertCase
#endif
/* Private variable declarations
*/
static int gdk_initialized = 0; /* 1 if the library is initialized,
* 0 otherwise.
*/
#ifdef G_ENABLE_DEBUG
static const GDebugKey gdk_debug_keys[] = {
{"misc", GDK_DEBUG_MISC},
{"events", GDK_DEBUG_EVENTS},
};
static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
#endif /* G_ENABLE_DEBUG */
GdkArgDesc _gdk_windowing_args[] = {
{ NULL }
};
static GdkFBDisplay *
gdk_fb_display_new(const char *filename)
{
int fd, n;
GdkFBDisplay *retval;
guint16 red[256], green[256], blue[256];
struct fb_cmap cmap;
fd = open(filename, O_RDWR);
if(fd < 0)
return NULL;
retval = g_new0(GdkFBDisplay, 1);
retval->fd = fd;
n = ioctl(fd, FBIOGET_FSCREENINFO, &retval->sinfo);
n |= ioctl(fd, FBIOGET_VSCREENINFO, &retval->modeinfo);
g_assert(!n);
retval->fbmem = mmap(NULL, retval->sinfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
g_assert(retval->fbmem != MAP_FAILED);
for(n = 0; n < 16; n++)
red[n] = green[n] = blue[n] = n << 12;
for(n = 16; n < 256; n++)
red[n] = green[n] = blue[n] = n << 8;
cmap.red = red; cmap.green = green; cmap.blue = blue; cmap.len = 256; cmap.start = 0;
ioctl(fd, FBIOPUTCMAP, &cmap);
return retval;
}
static void
gdk_fb_display_destroy(GdkFBDisplay *fbd)
{
munmap(fbd->fbmem, fbd->sinfo.smem_len);
g_free(fbd);
}
extern void keyboard_init(void);
gboolean
_gdk_windowing_init_check (int argc, char **argv)
{
if(gdk_initialized)
return TRUE;
keyboard_init();
gdk_display = gdk_fb_display_new("/dev/fb");
if(!gdk_display)
return FALSE;
T1_InitLib(NO_LOGFILE|IGNORE_FONTDATABASE);
T1_AASetBitsPerPixel(gdk_display->modeinfo.bits_per_pixel);
gdk_initialized = TRUE;
return TRUE;
}
/*
*--------------------------------------------------------------
* gdk_pointer_grab
*
* Grabs the pointer to a specific window
*
* Arguments:
* "window" is the window which will receive the grab
* "owner_events" specifies whether events will be reported as is,
* or relative to "window"
* "event_mask" masks only interesting events
* "confine_to" limits the cursor movement to the specified window
* "cursor" changes the cursor for the duration of the grab
* "time" specifies the time
*
* Results:
*
* Side effects:
* requires a corresponding call to gdk_pointer_ungrab
*
*--------------------------------------------------------------
*/
gint
gdk_pointer_grab (GdkWindow * window,
gint owner_events,
GdkEventMask event_mask,
GdkWindow * confine_to,
GdkCursor * cursor,
guint32 time)
{
g_return_val_if_fail (window != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
if(_gdk_fb_pointer_grab_window)
return 1;
if(!owner_events)
_gdk_fb_pointer_grab_window = gdk_window_ref(window);
_gdk_fb_pointer_grab_confine = confine_to?gdk_window_ref(confine_to):NULL;
_gdk_fb_pointer_grab_events = event_mask;
_gdk_fb_pointer_grab_cursor = cursor?gdk_cursor_ref(cursor):NULL;
return 0;
}
/*
*--------------------------------------------------------------
* gdk_pointer_ungrab
*
* Releases any pointer grab
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
void
gdk_pointer_ungrab (guint32 time)
{
if(_gdk_fb_pointer_grab_window)
gdk_window_unref(_gdk_fb_pointer_grab_window);
_gdk_fb_pointer_grab_window = NULL;
if(_gdk_fb_pointer_grab_confine)
gdk_window_unref(_gdk_fb_pointer_grab_confine);
_gdk_fb_pointer_grab_confine = NULL;
if(_gdk_fb_pointer_grab_cursor)
gdk_cursor_unref(_gdk_fb_pointer_grab_cursor);
_gdk_fb_pointer_grab_cursor = NULL;
}
/*
*--------------------------------------------------------------
* gdk_pointer_is_grabbed
*
* Tell wether there is an active x pointer grab in effect
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gint
gdk_pointer_is_grabbed (void)
{
return _gdk_fb_pointer_grab_window != NULL;
}
/*
*--------------------------------------------------------------
* gdk_keyboard_grab
*
* Grabs the keyboard to a specific window
*
* Arguments:
* "window" is the window which will receive the grab
* "owner_events" specifies whether events will be reported as is,
* or relative to "window"
* "time" specifies the time
*
* Results:
*
* Side effects:
* requires a corresponding call to gdk_keyboard_ungrab
*
*--------------------------------------------------------------
*/
gint
gdk_keyboard_grab (GdkWindow * window,
gint owner_events,
guint32 time)
{
g_return_val_if_fail (window != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
if(_gdk_fb_pointer_grab_window)
gdk_keyboard_ungrab(time);
if(!owner_events)
_gdk_fb_keyboard_grab_window = gdk_window_ref(window);
return 0;
}
/*
*--------------------------------------------------------------
* gdk_keyboard_ungrab
*
* Releases any keyboard grab
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
void
gdk_keyboard_ungrab (guint32 time)
{
if(_gdk_fb_keyboard_grab_window)
gdk_window_unref(_gdk_fb_keyboard_grab_window);
_gdk_fb_keyboard_grab_window = NULL;
}
/*
*--------------------------------------------------------------
* gdk_screen_width
*
* Return the width of the screen.
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gint
gdk_screen_width (void)
{
return gdk_display->modeinfo.xres;
}
/*
*--------------------------------------------------------------
* gdk_screen_height
*
* Return the height of the screen.
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gint
gdk_screen_height (void)
{
return gdk_display->modeinfo.yres;
}
/*
*--------------------------------------------------------------
* gdk_screen_width_mm
*
* Return the width of the screen in millimeters.
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gint
gdk_screen_width_mm (void)
{
return 0.5 + gdk_screen_width () * (25.4 / 72.);
}
/*
*--------------------------------------------------------------
* gdk_screen_height
*
* Return the height of the screen in millimeters.
*
* Arguments:
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
gint
gdk_screen_height_mm (void)
{
return 0.5 + gdk_screen_height () * (25.4 / 72.);
}
/*
*--------------------------------------------------------------
* gdk_set_sm_client_id
*
* Set the SM_CLIENT_ID property on the WM_CLIENT_LEADER window
* so that the window manager can save our state using the
* X11R6 ICCCM session management protocol. A NULL value should
* be set following disconnection from the session manager to
* remove the SM_CLIENT_ID property.
*
* Arguments:
*
* "sm_client_id" specifies the client id assigned to us by the
* session manager or NULL to remove the property.
*
* Results:
*
* Side effects:
*
*--------------------------------------------------------------
*/
void
gdk_set_sm_client_id (const gchar* sm_client_id)
{
}
void
gdk_key_repeat_disable (void)
{
}
void
gdk_key_repeat_restore (void)
{
}
void
gdk_beep (void)
{
}
extern void keyboard_shutdown(void);
void
gdk_windowing_exit (void)
{
gdk_fb_display_destroy(gdk_display); gdk_display = NULL;
T1_CloseLib();
keyboard_shutdown();
}
gchar*
gdk_keyval_name (guint keyval)
{
return NULL;
}
guint
gdk_keyval_from_name (const gchar *keyval_name)
{
return 0;
}
void gdk_keyval_convert_case (guint symbol,
guint *lower,
guint *upper)
{
if(symbol >= 'a' && symbol <= 'z')
symbol = toupper(symbol);
if(upper)
*upper = symbol;
if(lower)
*lower = symbol;
}
gchar *
gdk_get_display(void)
{
return g_strdup("/dev/fb0");
}
/* utils */
GdkEvent *
gdk_event_make(GdkWindow *window, GdkEventType type, gboolean append_to_queue)
{
static const guint type_masks[] = {
GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0, */
GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1, */
GDK_EXPOSURE_MASK, /* GDK_EXPOSE = 2, */
GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK, /* GDK_MOTION_NOTIFY = 3, */
GDK_BUTTON_PRESS_MASK, /* GDK_BUTTON_PRESS = 4, */
GDK_BUTTON_PRESS_MASK, /* GDK_2BUTTON_PRESS = 5, */
GDK_BUTTON_PRESS_MASK, /* GDK_3BUTTON_PRESS = 6, */
GDK_BUTTON_RELEASE_MASK, /* GDK_BUTTON_RELEASE = 7, */
GDK_KEY_PRESS_MASK, /* GDK_KEY_PRESS = 8, */
GDK_KEY_RELEASE_MASK, /* GDK_KEY_RELEASE = 9, */
GDK_ENTER_NOTIFY_MASK, /* GDK_ENTER_NOTIFY = 10, */
GDK_LEAVE_NOTIFY_MASK, /* GDK_LEAVE_NOTIFY = 11, */
GDK_FOCUS_CHANGE_MASK, /* GDK_FOCUS_CHANGE = 12, */
GDK_STRUCTURE_MASK, /* GDK_CONFIGURE = 13, */
GDK_VISIBILITY_NOTIFY_MASK, /* GDK_MAP = 14, */
GDK_VISIBILITY_NOTIFY_MASK, /* GDK_UNMAP = 15, */
GDK_PROPERTY_CHANGE_MASK, /* GDK_PROPERTY_NOTIFY = 16, */
GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_CLEAR = 17, */
GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_REQUEST = 18, */
GDK_PROPERTY_CHANGE_MASK, /* GDK_SELECTION_NOTIFY = 19, */
GDK_PROXIMITY_IN_MASK, /* GDK_PROXIMITY_IN = 20, */
GDK_PROXIMITY_OUT_MASK, /* GDK_PROXIMITY_OUT = 21, */
GDK_ALL_EVENTS_MASK, /* GDK_DRAG_ENTER = 22, */
GDK_ALL_EVENTS_MASK, /* GDK_DRAG_LEAVE = 23, */
GDK_ALL_EVENTS_MASK, /* GDK_DRAG_MOTION = 24, */
GDK_ALL_EVENTS_MASK, /* GDK_DRAG_STATUS = 25, */
GDK_ALL_EVENTS_MASK, /* GDK_DROP_START = 26, */
GDK_ALL_EVENTS_MASK, /* GDK_DROP_FINISHED = 27, */
GDK_ALL_EVENTS_MASK, /* GDK_CLIENT_EVENT = 28, */
GDK_VISIBILITY_NOTIFY_MASK, /* GDK_VISIBILITY_NOTIFY = 29, */
GDK_EXPOSURE_MASK, /* GDK_NO_EXPOSE = 30, */
GDK_SCROLL_MASK /* GDK_SCROLL = 31 */
};
if(GDK_WINDOW_FBDATA(window)->event_mask & type_masks[type])
{
GdkEvent *event = gdk_event_new();
guint32 the_time = g_latest_time.tv_sec;
event->any.type = type;
event->any.window = gdk_window_ref(window);
switch(type)
{
case GDK_MOTION_NOTIFY:
event->motion.time = the_time;
break;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
event->button.time = the_time;
break;
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
event->key.time = the_time;
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
event->crossing.time = the_time;
break;
case GDK_PROPERTY_NOTIFY:
event->property.time = the_time;
break;
case GDK_SELECTION_CLEAR:
case GDK_SELECTION_REQUEST:
case GDK_SELECTION_NOTIFY:
event->selection.time = the_time;
break;
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
event->proximity.time = the_time;
break;
case GDK_DRAG_ENTER:
case GDK_DRAG_LEAVE:
case GDK_DRAG_MOTION:
case GDK_DRAG_STATUS:
case GDK_DROP_START:
case GDK_DROP_FINISHED:
event->dnd.time = the_time;
break;
case GDK_FOCUS_CHANGE:
case GDK_CONFIGURE:
case GDK_MAP:
case GDK_UNMAP:
case GDK_CLIENT_EVENT:
case GDK_VISIBILITY_NOTIFY:
case GDK_NO_EXPOSE:
case GDK_SCROLL:
case GDK_DELETE:
case GDK_DESTROY:
case GDK_EXPOSE:
default:
break;
}
if(append_to_queue)
gdk_event_queue_append(event);
return event;
}
return NULL;
}

768
gdk/linux-fb/gdkpixmap-fb.c Normal file
View File

@ -0,0 +1,768 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Needed for SEEK_END in SunOS */
#include <unistd.h>
#include "gdkpixmap.h"
#include "gdkfb.h"
#include "gdkprivate-fb.h"
typedef struct
{
gchar *color_string;
GdkColor color;
gint transparent;
} _GdkPixmapColor;
typedef struct
{
guint ncolors;
GdkColormap *colormap;
gulong pixels[1];
} _GdkPixmapInfo;
static void
gdk_fb_pixmap_destroy (GdkPixmap *pixmap)
{
g_free (GDK_DRAWABLE_FBDATA(pixmap)->mem);
g_free (GDK_DRAWABLE_FBDATA (pixmap));
}
static GdkDrawable *
gdk_fb_pixmap_alloc (void)
{
GdkDrawable *drawable;
GdkDrawablePrivate *private;
static GdkDrawableClass klass;
static gboolean initialized = FALSE;
if (!initialized)
{
initialized = TRUE;
klass = _gdk_fb_drawable_class;
klass.destroy = gdk_fb_pixmap_destroy;
}
drawable = gdk_drawable_alloc ();
private = (GdkDrawablePrivate *)drawable;
private->klass = &klass;
private->klass_data = g_new0 (GdkDrawableFBData, 1);
private->window_type = GDK_DRAWABLE_PIXMAP;
private->colormap = gdk_colormap_ref(gdk_colormap_get_system());
return drawable;
}
GdkPixmap*
gdk_pixmap_new (GdkWindow *window,
gint width,
gint height,
gint depth)
{
GdkPixmap *pixmap;
GdkDrawablePrivate *private;
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
g_return_val_if_fail ((width != 0) && (height != 0), NULL);
if (!window)
window = gdk_parent_root;
if (GDK_DRAWABLE_DESTROYED (window))
return NULL;
if (depth == -1)
depth = gdk_drawable_get_visual (window)->depth;
pixmap = gdk_fb_pixmap_alloc ();
private = (GdkDrawablePrivate *)pixmap;
GDK_DRAWABLE_FBDATA(pixmap)->mem = g_malloc(((width * depth + 7) / 8) * height);
GDK_DRAWABLE_FBDATA(pixmap)->rowstride = (width * depth + 7) / 8; /* Round up to nearest whole byte */
GDK_DRAWABLE_FBDATA(pixmap)->lim_x = width;
GDK_DRAWABLE_FBDATA(pixmap)->lim_y = height;
private->width = width;
private->height = height;
private->depth = depth;
return pixmap;
}
GdkPixmap *
gdk_bitmap_create_from_data (GdkWindow *window,
const gchar *data,
gint width,
gint height)
{
GdkPixmap *pixmap;
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail ((width != 0) && (height != 0), NULL);
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
if (!window)
window = gdk_parent_root;
if (GDK_DRAWABLE_DESTROYED (window))
return NULL;
pixmap = gdk_pixmap_new(window, width, height, 1);
memcpy(GDK_DRAWABLE_FBDATA(pixmap)->mem, data, ((width + 7) / 8) * height);
return pixmap;
}
GdkPixmap*
gdk_pixmap_create_from_data (GdkWindow *window,
const gchar *data,
gint width,
gint height,
gint depth,
GdkColor *fg,
GdkColor *bg)
{
GdkPixmap *pixmap;
GdkDrawablePrivate *private;
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (fg != NULL, NULL);
g_return_val_if_fail (bg != NULL, NULL);
g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
g_return_val_if_fail ((width != 0) && (height != 0), NULL);
if (!window)
window = gdk_parent_root;
if (GDK_DRAWABLE_DESTROYED (window))
return NULL;
if (depth == -1)
depth = gdk_drawable_get_visual (window)->depth;
pixmap = gdk_pixmap_new(window, width, height, depth);
private = (GdkDrawablePrivate *)pixmap;
return pixmap;
}
static gint
gdk_pixmap_seek_string (FILE *infile,
const gchar *str,
gint skip_comments)
{
char instr[1024];
while (!feof (infile))
{
fscanf (infile, "%1023s", instr);
if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
{
fscanf (infile, "%1023s", instr);
while (!feof (infile) && strcmp (instr, "*/") != 0)
fscanf (infile, "%1023s", instr);
fscanf(infile, "%1023s", instr);
}
if (strcmp (instr, str)==0)
return TRUE;
}
return FALSE;
}
static gint
gdk_pixmap_seek_char (FILE *infile,
gchar c)
{
gint b, oldb;
while ((b = getc(infile)) != EOF)
{
if (c != b && b == '/')
{
b = getc (infile);
if (b == EOF)
return FALSE;
else if (b == '*') /* we have a comment */
{
b = -1;
do
{
oldb = b;
b = getc (infile);
if (b == EOF)
return FALSE;
}
while (!(oldb == '*' && b == '/'));
}
}
else if (c == b)
return TRUE;
}
return FALSE;
}
static gint
gdk_pixmap_read_string (FILE *infile,
gchar **buffer,
guint *buffer_size)
{
gint c;
guint cnt = 0, bufsiz, ret = FALSE;
gchar *buf;
buf = *buffer;
bufsiz = *buffer_size;
if (buf == NULL)
{
bufsiz = 10 * sizeof (gchar);
buf = g_new(gchar, bufsiz);
}
do
c = getc (infile);
while (c != EOF && c != '"');
if (c != '"')
goto out;
while ((c = getc(infile)) != EOF)
{
if (cnt == bufsiz)
{
guint new_size = bufsiz * 2;
if (new_size > bufsiz)
bufsiz = new_size;
else
goto out;
buf = (gchar *) g_realloc (buf, bufsiz);
buf[bufsiz-1] = '\0';
}
if (c != '"')
buf[cnt++] = c;
else
{
buf[cnt] = 0;
ret = TRUE;
break;
}
}
out:
buf[bufsiz-1] = '\0'; /* ensure null termination for errors */
*buffer = buf;
*buffer_size = bufsiz;
return ret;
}
static gchar*
gdk_pixmap_skip_whitespaces (gchar *buffer)
{
gint32 index = 0;
while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
index++;
return &buffer[index];
}
static gchar*
gdk_pixmap_skip_string (gchar *buffer)
{
gint32 index = 0;
while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
index++;
return &buffer[index];
}
/* Xlib crashed once at a color name lengths around 125 */
#define MAX_COLOR_LEN 120
static gchar*
gdk_pixmap_extract_color (gchar *buffer)
{
gint counter, numnames;
gchar *ptr = NULL, ch, temp[128];
gchar color[MAX_COLOR_LEN], *retcol;
gint space;
counter = 0;
while (ptr == NULL)
{
if (buffer[counter] == 'c')
{
ch = buffer[counter + 1];
if (ch == 0x20 || ch == 0x09)
ptr = &buffer[counter + 1];
}
else if (buffer[counter] == 0)
return NULL;
counter++;
}
ptr = gdk_pixmap_skip_whitespaces (ptr);
if (ptr[0] == 0)
return NULL;
else if (ptr[0] == '#')
{
counter = 1;
while (ptr[counter] != 0 &&
((ptr[counter] >= '0' && ptr[counter] <= '9') ||
(ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
(ptr[counter] >= 'A' && ptr[counter] <= 'F')))
counter++;
retcol = g_new (gchar, counter+1);
strncpy (retcol, ptr, counter);
retcol[counter] = 0;
return retcol;
}
color[0] = 0;
numnames = 0;
space = MAX_COLOR_LEN - 1;
while (space > 0)
{
sscanf (ptr, "%127s", temp);
if (((gint)ptr[0] == 0) ||
(strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
(strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
{
break;
}
else
{
if (numnames > 0)
{
space -= 1;
strcat (color, " ");
}
strncat (color, temp, space);
space -= MIN (space, strlen (temp));
ptr = gdk_pixmap_skip_string (ptr);
ptr = gdk_pixmap_skip_whitespaces (ptr);
numnames++;
}
}
retcol = g_strdup (color);
return retcol;
}
enum buffer_op
{
op_header,
op_cmap,
op_body
};
static void
gdk_xpm_destroy_notify (gpointer data)
{
_GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
GdkColor color;
int i;
for (i=0; i<info->ncolors; i++)
{
color.pixel = info->pixels[i];
gdk_colormap_free_colors (info->colormap, &color, 1);
}
gdk_colormap_unref (info->colormap);
g_free (info);
}
static GdkPixmap *
_gdk_pixmap_create_from_xpm (GdkWindow *window,
GdkColormap *colormap,
GdkBitmap **mask,
GdkColor *transparent_color,
gchar * (*get_buf) (enum buffer_op op,
gpointer handle),
gpointer handle)
{
GdkPixmap *pixmap = NULL;
GdkImage *image = NULL;
GdkVisual *visual;
GdkGC *gc = NULL;
GdkColor tmp_color;
gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
gchar *buffer, pixel_str[32];
gchar *name_buf;
_GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
_GdkPixmapColor *colors = NULL;
gulong index;
GHashTable *color_hash = NULL;
_GdkPixmapInfo *color_info = NULL;
if ((window == NULL) && (colormap == NULL))
g_warning ("Creating pixmap from xpm with NULL window and colormap");
if (window == NULL)
window = gdk_parent_root;
if (colormap == NULL)
{
colormap = gdk_drawable_get_colormap (window);
visual = gdk_drawable_get_visual (window);
}
else
visual = ((GdkColormapPrivate *)colormap)->visual;
buffer = (*get_buf) (op_header, handle);
if (buffer == NULL)
return NULL;
sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
if (cpp >= 32)
{
g_warning ("Pixmap has more than 31 characters per color\n");
return NULL;
}
color_hash = g_hash_table_new (g_str_hash, g_str_equal);
if (transparent_color == NULL)
{
gdk_color_white (colormap, &tmp_color);
transparent_color = &tmp_color;
}
/* For pseudo-color and grayscale visuals, we have to remember
* the colors we allocated, so we can free them later.
*/
if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
(visual->type == GDK_VISUAL_GRAYSCALE))
{
color_info = g_malloc (sizeof (_GdkPixmapInfo) +
sizeof(gulong) * (num_cols - 1));
color_info->ncolors = num_cols;
color_info->colormap = colormap;
gdk_colormap_ref (colormap);
}
name_buf = g_new (gchar, num_cols * (cpp+1));
colors = g_new (_GdkPixmapColor, num_cols);
for (cnt = 0; cnt < num_cols; cnt++)
{
gchar *color_name;
buffer = (*get_buf) (op_cmap, handle);
if (buffer == NULL)
goto error;
color = &colors[cnt];
color->color_string = &name_buf [cnt * (cpp + 1)];
strncpy (color->color_string, buffer, cpp);
color->color_string[cpp] = 0;
buffer += strlen (color->color_string);
color->transparent = FALSE;
color_name = gdk_pixmap_extract_color (buffer);
if (color_name == NULL || g_strcasecmp (color_name, "None") == 0 ||
gdk_color_parse (color_name, &color->color) == FALSE)
{
color->color = *transparent_color;
color->transparent = TRUE;
}
g_free (color_name);
/* FIXME: The remaining slowness appears to happen in this
function. */
gdk_color_alloc (colormap, &color->color);
if (color_info)
color_info->pixels[cnt] = color->color.pixel;
g_hash_table_insert (color_hash, color->color_string, color);
if (cnt == 0)
fallbackcolor = color;
}
index = 0;
image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
if (mask)
{
/* The pixmap mask is just a bits pattern.
* Color 0 is used for background and 1 for foreground.
* We don't care about the colormap, we just need 0 and 1.
*/
GdkColor mask_pattern;
*mask = gdk_pixmap_new (window, width, height, 1);
gc = gdk_gc_new (*mask);
mask_pattern.pixel = 0;
gdk_gc_set_foreground (gc, &mask_pattern);
gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, width, height);
mask_pattern.pixel = 255;
gdk_gc_set_foreground (gc, &mask_pattern);
}
wbytes = width * cpp;
for (ycnt = 0; ycnt < height; ycnt++)
{
buffer = (*get_buf) (op_body, handle);
/* FIXME: this slows things down a little - it could be
* integrated into the strncpy below, perhaps. OTOH, strlen
* is fast.
*/
if ((buffer == NULL) || strlen (buffer) < wbytes)
continue;
for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
{
strncpy (pixel_str, &buffer[n], cpp);
pixel_str[cpp] = 0;
ns = 0;
color = g_hash_table_lookup (color_hash, pixel_str);
if (!color) /* screwed up XPM file */
color = fallbackcolor;
gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
if (mask && color->transparent)
{
if (cnt < xcnt)
gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
cnt = xcnt + 1;
}
}
if (mask && (cnt < xcnt))
gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
}
error:
if (mask)
gdk_gc_unref (gc);
if (image != NULL)
{
pixmap = gdk_pixmap_new (window, width, height, visual->depth);
if (color_info)
gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
gdk_xpm_destroy_notify);
gc = gdk_gc_new (pixmap);
gdk_gc_set_foreground (gc, transparent_color);
gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
gdk_gc_unref (gc);
gdk_image_unref (image);
#if 0
g_print("%dx%d\n", width, height);
for(y = 0; y < height; y++)
{
for(x = 0; x < width; x++)
{
guchar foo = GDK_DRAWABLE_FBDATA(pixmap)->mem[(x + GDK_DRAWABLE_FBDATA(pixmap)->rowstride * y];
if(foo == 0)
g_print("o");
else if(foo == 255)
g_print("w");
else if(foo == transparent_color->pixel)
g_print(" ");
else
g_print(".");
}
g_print("\n");
}
#endif
}
else if (color_info)
gdk_xpm_destroy_notify (color_info);
if (color_hash != NULL)
g_hash_table_destroy (color_hash);
if (colors != NULL)
g_free (colors);
if (name_buf != NULL)
g_free (name_buf);
return pixmap;
}
struct file_handle
{
FILE *infile;
gchar *buffer;
guint buffer_size;
};
static gchar *
file_buffer (enum buffer_op op, gpointer handle)
{
struct file_handle *h = handle;
switch (op)
{
case op_header:
if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
break;
if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
break;
/* Fall through to the next gdk_pixmap_seek_char. */
case op_cmap:
gdk_pixmap_seek_char (h->infile, '"');
fseek (h->infile, -1, SEEK_CUR);
/* Fall through to the gdk_pixmap_read_string. */
case op_body:
gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
return h->buffer;
}
return 0;
}
GdkPixmap*
gdk_pixmap_colormap_create_from_xpm (GdkWindow *window,
GdkColormap *colormap,
GdkBitmap **mask,
GdkColor *transparent_color,
const gchar *filename)
{
struct file_handle h;
GdkPixmap *pixmap = NULL;
memset (&h, 0, sizeof (h));
h.infile = fopen (filename, "rb");
if (h.infile != NULL)
{
pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
transparent_color,
file_buffer, &h);
fclose (h.infile);
g_free (h.buffer);
}
return pixmap;
}
GdkPixmap*
gdk_pixmap_create_from_xpm (GdkWindow *window,
GdkBitmap **mask,
GdkColor *transparent_color,
const gchar *filename)
{
return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
transparent_color, filename);
}
struct mem_handle
{
gchar **data;
int offset;
};
static gchar *
mem_buffer (enum buffer_op op, gpointer handle)
{
struct mem_handle *h = handle;
switch (op)
{
case op_header:
case op_cmap:
case op_body:
if (h->data[h->offset])
return h->data[h->offset ++];
}
return 0;
}
GdkPixmap*
gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window,
GdkColormap *colormap,
GdkBitmap **mask,
GdkColor *transparent_color,
gchar **data)
{
struct mem_handle h;
GdkPixmap *pixmap = NULL;
memset (&h, 0, sizeof (h));
h.data = data;
pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
transparent_color,
mem_buffer, &h);
return pixmap;
}
GdkPixmap*
gdk_pixmap_create_from_xpm_d (GdkWindow *window,
GdkBitmap **mask,
GdkColor *transparent_color,
gchar **data)
{
return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
transparent_color, data);
}

View File

@ -0,0 +1,291 @@
/* $TOG: poly.h /main/5 1998/02/06 17:47:27 kaleb $ */
/************************************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
/*
* This file contains a few macros to help track
* the edge of a filled object. The object is assumed
* to be filled in scanline order, and thus the
* algorithm used is an extension of Bresenham's line
* drawing algorithm which assumes that y is always the
* major axis.
* Since these pieces of code are the same for any filled shape,
* it is more convenient to gather the library in one
* place, but since these pieces of code are also in
* the inner loops of output primitives, procedure call
* overhead is out of the question.
* See the author for a derivation if needed.
*/
/*
* In scan converting polygons, we want to choose those pixels
* which are inside the polygon. Thus, we add .5 to the starting
* x coordinate for both left and right edges. Now we choose the
* first pixel which is inside the pgon for the left edge and the
* first pixel which is outside the pgon for the right edge.
* Draw the left pixel, but not the right.
*
* How to add .5 to the starting x coordinate:
* If the edge is moving to the right, then subtract dy from the
* error term from the general form of the algorithm.
* If the edge is moving to the left, then add dy to the error term.
*
* The reason for the difference between edges moving to the left
* and edges moving to the right is simple: If an edge is moving
* to the right, then we want the algorithm to flip immediately.
* If it is moving to the left, then we don't want it to flip until
* we traverse an entire pixel.
*/
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
int dx; /* local storage */ \
\
/* \
* if the edge is horizontal, then it is ignored \
* and assumed not to be processed. Otherwise, do this stuff. \
*/ \
if ((dy) != 0) { \
xStart = (x1); \
dx = (x2) - xStart; \
if (dx < 0) { \
m = dx / (dy); \
m1 = m - 1; \
incr1 = -2 * dx + 2 * (dy) * m1; \
incr2 = -2 * dx + 2 * (dy) * m; \
d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
} else { \
m = dx / (dy); \
m1 = m + 1; \
incr1 = 2 * dx - 2 * (dy) * m1; \
incr2 = 2 * dx - 2 * (dy) * m; \
d = -2 * m * (dy) + 2 * dx; \
} \
} \
}
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
if (m1 > 0) { \
if (d > 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} else {\
if (d >= 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} \
}
/*
* This structure contains all of the information needed
* to run the bresenham algorithm.
* The variables may be hardcoded into the declarations
* instead of using this structure to make use of
* register declarations.
*/
typedef struct {
int minor_axis; /* minor axis */
int d; /* decision variable */
int m, m1; /* slope and slope+1 */
int incr1, incr2; /* error increments */
} BRESINFO;
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
bres.m, bres.m1, bres.incr1, bres.incr2)
#define BRESINCRPGONSTRUCT(bres) \
BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
/*
* These are the data structures needed to scan
* convert regions. Two different scan conversion
* methods are available -- the even-odd method, and
* the winding number method.
* The even-odd rule states that a point is inside
* the polygon if a ray drawn from that point in any
* direction will pass through an odd number of
* path segments.
* By the winding number rule, a point is decided
* to be inside the polygon if a ray drawn from that
* point in any direction passes through a different
* number of clockwise and counter-clockwise path
* segments.
*
* These data structures are adapted somewhat from
* the algorithm in (Foley/Van Dam) for scan converting
* polygons.
* The basic algorithm is to start at the top (smallest y)
* of the polygon, stepping down to the bottom of
* the polygon by incrementing the y coordinate. We
* keep a list of edges which the current scanline crosses,
* sorted by x. This list is called the Active Edge Table (AET)
* As we change the y-coordinate, we update each entry in
* in the active edge table to reflect the edges new xcoord.
* This list must be sorted at each scanline in case
* two edges intersect.
* We also keep a data structure known as the Edge Table (ET),
* which keeps track of all the edges which the current
* scanline has not yet reached. The ET is basically a
* list of ScanLineList structures containing a list of
* edges which are entered at a given scanline. There is one
* ScanLineList per scanline at which an edge is entered.
* When we enter a new edge, we move it from the ET to the AET.
*
* From the AET, we can implement the even-odd rule as in
* (Foley/Van Dam).
* The winding number rule is a little trickier. We also
* keep the EdgeTableEntries in the AET linked by the
* nextWETE (winding EdgeTableEntry) link. This allows
* the edges to be linked just as before for updating
* purposes, but only uses the edges linked by the nextWETE
* link as edges representing spans of the polygon to
* drawn (as with the even-odd rule).
*/
/*
* for the winding number rule
*/
#define CLOCKWISE 1
#define COUNTERCLOCKWISE -1
typedef struct _EdgeTableEntry {
int ymax; /* ycoord at which we exit this edge. */
BRESINFO bres; /* Bresenham info to run the edge */
struct _EdgeTableEntry *next; /* next in the list */
struct _EdgeTableEntry *back; /* for insertion sort */
struct _EdgeTableEntry *nextWETE; /* for winding num rule */
int ClockWise; /* flag for winding number rule */
} EdgeTableEntry;
typedef struct _ScanLineList{
int scanline; /* the scanline represented */
EdgeTableEntry *edgelist; /* header node */
struct _ScanLineList *next; /* next in the list */
} ScanLineList;
typedef struct {
int ymax; /* ymax for the polygon */
int ymin; /* ymin for the polygon */
ScanLineList scanlines; /* header node */
} EdgeTable;
/*
* Here is a struct to help with storage allocation
* so we can allocate a big chunk at a time, and then take
* pieces from this heap when we need to.
*/
#define SLLSPERBLOCK 25
typedef struct _ScanLineListBlock {
ScanLineList SLLs[SLLSPERBLOCK];
struct _ScanLineListBlock *next;
} ScanLineListBlock;
/*
*
* a few macros for the inner loops of the fill code where
* performance considerations don't allow a procedure call.
*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The winding number rule is in effect, so we must notify
* the caller when the edge has been removed so he
* can reorder the Winding Active Edge Table.
*/
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
fixWAET = 1; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}
/*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The even-odd rule is in effect.
*/
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}

View File

@ -0,0 +1,616 @@
/* $TOG: PolyReg.c /main/15 1998/02/06 17:47:08 kaleb $ */
/************************************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
/* $XFree86: xc/lib/X11/PolyReg.c,v 1.4 1998/10/03 08:41:21 dawes Exp $ */
#define LARGE_COORDINATE 1000000
#define SMALL_COORDINATE -LARGE_COORDINATE
#include <gdkregion.h>
#include "gdkregion-generic.h"
#include "gdkpoly-generic.h"
/*
* InsertEdgeInET
*
* Insert the given edge into the edge table.
* First we must find the correct bucket in the
* Edge table, then find the right slot in the
* bucket. Finally, we can insert it.
*
*/
static void
InsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
EdgeTable *ET;
EdgeTableEntry *ETE;
int scanline;
ScanLineListBlock **SLLBlock;
int *iSLLBlock;
{
EdgeTableEntry *start, *prev;
ScanLineList *pSLL, *pPrevSLL;
ScanLineListBlock *tmpSLLBlock;
/*
* find the right bucket to put the edge into
*/
pPrevSLL = &ET->scanlines;
pSLL = pPrevSLL->next;
while (pSLL && (pSLL->scanline < scanline))
{
pPrevSLL = pSLL;
pSLL = pSLL->next;
}
/*
* reassign pSLL (pointer to ScanLineList) if necessary
*/
if ((!pSLL) || (pSLL->scanline > scanline))
{
if (*iSLLBlock > SLLSPERBLOCK-1)
{
tmpSLLBlock =
(ScanLineListBlock *)g_malloc(sizeof(ScanLineListBlock));
(*SLLBlock)->next = tmpSLLBlock;
tmpSLLBlock->next = (ScanLineListBlock *)NULL;
*SLLBlock = tmpSLLBlock;
*iSLLBlock = 0;
}
pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
pSLL->next = pPrevSLL->next;
pSLL->edgelist = (EdgeTableEntry *)NULL;
pPrevSLL->next = pSLL;
}
pSLL->scanline = scanline;
/*
* now insert the edge in the right bucket
*/
prev = (EdgeTableEntry *)NULL;
start = pSLL->edgelist;
while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
{
prev = start;
start = start->next;
}
ETE->next = start;
if (prev)
prev->next = ETE;
else
pSLL->edgelist = ETE;
}
/*
* CreateEdgeTable
*
* This routine creates the edge table for
* scan converting polygons.
* The Edge Table (ET) looks like:
*
* EdgeTable
* --------
* | ymax | ScanLineLists
* |scanline|-->------------>-------------->...
* -------- |scanline| |scanline|
* |edgelist| |edgelist|
* --------- ---------
* | |
* | |
* V V
* list of ETEs list of ETEs
*
* where ETE is an EdgeTableEntry data structure,
* and there is one ScanLineList per scanline at
* which an edge is initially entered.
*
*/
static void
CreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
int count;
GdkPoint *pts;
EdgeTable *ET;
EdgeTableEntry *AET;
EdgeTableEntry *pETEs;
ScanLineListBlock *pSLLBlock;
{
GdkPoint *top, *bottom;
GdkPoint *PrevPt, *CurrPt;
int iSLLBlock = 0;
int dy;
if (count < 2) return;
/*
* initialize the Active Edge Table
*/
AET->next = (EdgeTableEntry *)NULL;
AET->back = (EdgeTableEntry *)NULL;
AET->nextWETE = (EdgeTableEntry *)NULL;
AET->bres.minor_axis = SMALL_COORDINATE;
/*
* initialize the Edge Table.
*/
ET->scanlines.next = (ScanLineList *)NULL;
ET->ymax = SMALL_COORDINATE;
ET->ymin = LARGE_COORDINATE;
pSLLBlock->next = (ScanLineListBlock *)NULL;
PrevPt = &pts[count-1];
/*
* for each vertex in the array of points.
* In this loop we are dealing with two vertices at
* a time -- these make up one edge of the polygon.
*/
while (count--)
{
CurrPt = pts++;
/*
* find out which point is above and which is below.
*/
if (PrevPt->y > CurrPt->y)
{
bottom = PrevPt, top = CurrPt;
pETEs->ClockWise = 0;
}
else
{
bottom = CurrPt, top = PrevPt;
pETEs->ClockWise = 1;
}
/*
* don't add horizontal edges to the Edge table.
*/
if (bottom->y != top->y)
{
pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
/*
* initialize integer edge algorithm
*/
dy = bottom->y - top->y;
BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
if (PrevPt->y > ET->ymax)
ET->ymax = PrevPt->y;
if (PrevPt->y < ET->ymin)
ET->ymin = PrevPt->y;
pETEs++;
}
PrevPt = CurrPt;
}
}
/*
* loadAET
*
* This routine moves EdgeTableEntries from the
* EdgeTable into the Active Edge Table,
* leaving them sorted by smaller x coordinate.
*
*/
static void
loadAET(AET, ETEs)
EdgeTableEntry *AET, *ETEs;
{
EdgeTableEntry *pPrevAET;
EdgeTableEntry *tmp;
pPrevAET = AET;
AET = AET->next;
while (ETEs)
{
while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
{
pPrevAET = AET;
AET = AET->next;
}
tmp = ETEs->next;
ETEs->next = AET;
if (AET)
AET->back = ETEs;
ETEs->back = pPrevAET;
pPrevAET->next = ETEs;
pPrevAET = ETEs;
ETEs = tmp;
}
}
/*
* computeWAET
*
* This routine links the AET by the
* nextWETE (winding EdgeTableEntry) link for
* use by the winding number rule. The final
* Active Edge Table (AET) might look something
* like:
*
* AET
* ---------- --------- ---------
* |ymax | |ymax | |ymax |
* | ... | |... | |... |
* |next |->|next |->|next |->...
* |nextWETE| |nextWETE| |nextWETE|
* --------- --------- ^--------
* | | |
* V-------------------> V---> ...
*
*/
static void
computeWAET(AET)
EdgeTableEntry *AET;
{
EdgeTableEntry *pWETE;
int inside = 1;
int isInside = 0;
AET->nextWETE = (EdgeTableEntry *)NULL;
pWETE = AET;
AET = AET->next;
while (AET)
{
if (AET->ClockWise)
isInside++;
else
isInside--;
if ((!inside && !isInside) ||
( inside && isInside))
{
pWETE->nextWETE = AET;
pWETE = AET;
inside = !inside;
}
AET = AET->next;
}
pWETE->nextWETE = (EdgeTableEntry *)NULL;
}
/*
* InsertionSort
*
* Just a simple insertion sort using
* pointers and back pointers to sort the Active
* Edge Table.
*
*/
static int
InsertionSort(AET)
EdgeTableEntry *AET;
{
EdgeTableEntry *pETEchase;
EdgeTableEntry *pETEinsert;
EdgeTableEntry *pETEchaseBackTMP;
int changed = 0;
AET = AET->next;
while (AET)
{
pETEinsert = AET;
pETEchase = AET;
while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
pETEchase = pETEchase->back;
AET = AET->next;
if (pETEchase != pETEinsert)
{
pETEchaseBackTMP = pETEchase->back;
pETEinsert->back->next = AET;
if (AET)
AET->back = pETEinsert->back;
pETEinsert->next = pETEchase;
pETEchase->back->next = pETEinsert;
pETEchase->back = pETEinsert;
pETEinsert->back = pETEchaseBackTMP;
changed = 1;
}
}
return(changed);
}
/*
* Clean up our act.
*/
static void
FreeStorage(pSLLBlock)
ScanLineListBlock *pSLLBlock;
{
ScanLineListBlock *tmpSLLBlock;
while (pSLLBlock)
{
tmpSLLBlock = pSLLBlock->next;
g_free (pSLLBlock);
pSLLBlock = tmpSLLBlock;
}
}
/*
* Create an array of rectangles from a list of points.
* If indeed these things (POINTS, RECTS) are the same,
* then this proc is still needed, because it allocates
* storage for the array, which was allocated on the
* stack by the calling procedure.
*
*/
static int PtsToRegion(numFullPtBlocks, iCurPtBlock, FirstPtBlock, reg)
int numFullPtBlocks, iCurPtBlock;
POINTBLOCK *FirstPtBlock;
GdkRegion *reg;
{
GdkRegionBox *rects;
GdkPoint *pts;
POINTBLOCK *CurPtBlock;
int i;
GdkRegionBox *extents;
int numRects;
extents = &reg->extents;
numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
reg->rects = g_renew (GdkRegionBox, reg->rects, numRects);
reg->size = numRects;
CurPtBlock = FirstPtBlock;
rects = reg->rects - 1;
numRects = 0;
extents->x1 = G_MAXSHORT, extents->x2 = G_MINSHORT;
for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
/* the loop uses 2 points per iteration */
i = NUMPTSTOBUFFER >> 1;
if (!numFullPtBlocks)
i = iCurPtBlock >> 1;
for (pts = CurPtBlock->pts; i--; pts += 2) {
if (pts->x == pts[1].x)
continue;
if (numRects && pts->x == rects->x1 && pts->y == rects->y2 &&
pts[1].x == rects->x2 &&
(numRects == 1 || rects[-1].y1 != rects->y1) &&
(i && pts[2].y > pts[1].y)) {
rects->y2 = pts[1].y + 1;
continue;
}
numRects++;
rects++;
rects->x1 = pts->x; rects->y1 = pts->y;
rects->x2 = pts[1].x; rects->y2 = pts[1].y + 1;
if (rects->x1 < extents->x1)
extents->x1 = rects->x1;
if (rects->x2 > extents->x2)
extents->x2 = rects->x2;
}
CurPtBlock = CurPtBlock->next;
}
if (numRects) {
extents->y1 = reg->rects->y1;
extents->y2 = rects->y2;
} else {
extents->x1 = 0;
extents->y1 = 0;
extents->x2 = 0;
extents->y2 = 0;
}
reg->numRects = numRects;
return(TRUE);
}
/*
* polytoregion
*
* Scan converts a polygon by returning a run-length
* encoding of the resultant bitmap -- the run-length
* encoding is in the form of an array of rectangles.
*/
GdkRegion *
gdk_region_polygon(GdkPoint *Pts, gint Count, GdkFillRule rule)
{
GdkRegion *region;
EdgeTableEntry *pAET; /* Active Edge Table */
int y; /* current scanline */
int iPts = 0; /* number of pts in buffer */
EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
ScanLineList *pSLL; /* current scanLineList */
GdkPoint *pts; /* output buffer */
EdgeTableEntry *pPrevAET; /* ptr to previous AET */
EdgeTable ET; /* header node for ET */
EdgeTableEntry AET; /* header node for AET */
EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
ScanLineListBlock SLLBlock; /* header for scanlinelist */
int fixWAET = FALSE;
POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
POINTBLOCK *tmpPtBlock;
int numFullPtBlocks = 0;
region = gdk_region_new ();
/* special case a rectangle */
pts = Pts;
if (((Count == 4) ||
((Count == 5) && (pts[4].x == pts[0].x) && (pts[4].y == pts[0].y))) &&
(((pts[0].y == pts[1].y) &&
(pts[1].x == pts[2].x) &&
(pts[2].y == pts[3].y) &&
(pts[3].x == pts[0].x)) ||
((pts[0].x == pts[1].x) &&
(pts[1].y == pts[2].y) &&
(pts[2].x == pts[3].x) &&
(pts[3].y == pts[0].y)))) {
region->extents.x1 = MIN(pts[0].x, pts[2].x);
region->extents.y1 = MIN(pts[0].y, pts[2].y);
region->extents.x2 = MAX(pts[0].x, pts[2].x);
region->extents.y2 = MAX(pts[0].y, pts[2].y);
if ((region->extents.x1 != region->extents.x2) &&
(region->extents.y1 != region->extents.y2)) {
region->numRects = 1;
*(region->rects) = region->extents;
}
return(region);
}
pETEs = g_new (EdgeTableEntry, Count);
pts = FirstPtBlock.pts;
CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
pSLL = ET.scanlines.next;
curPtBlock = &FirstPtBlock;
if (rule == GDK_EVEN_ODD_RULE) {
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++) {
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL != NULL && y == pSLL->scanline) {
loadAET(&AET, pSLL->edgelist);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
/*
* for each active edge
*/
while (pAET) {
pts->x = pAET->bres.minor_axis, pts->y = y;
pts++, iPts++;
/*
* send out the buffer
*/
if (iPts == NUMPTSTOBUFFER) {
tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
curPtBlock->next = tmpPtBlock;
curPtBlock = tmpPtBlock;
pts = curPtBlock->pts;
numFullPtBlocks++;
iPts = 0;
}
EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
}
(void) InsertionSort(&AET);
}
}
else {
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++) {
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL != NULL && y == pSLL->scanline) {
loadAET(&AET, pSLL->edgelist);
computeWAET(&AET);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
pWETE = pAET;
/*
* for each active edge
*/
while (pAET) {
/*
* add to the buffer only those edges that
* are in the Winding active edge table.
*/
if (pWETE == pAET) {
pts->x = pAET->bres.minor_axis, pts->y = y;
pts++, iPts++;
/*
* send out the buffer
*/
if (iPts == NUMPTSTOBUFFER) {
tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
curPtBlock->next = tmpPtBlock;
curPtBlock = tmpPtBlock;
pts = curPtBlock->pts;
numFullPtBlocks++; iPts = 0;
}
pWETE = pWETE->nextWETE;
}
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
}
/*
* recompute the winding active edge table if
* we just resorted or have exited an edge.
*/
if (InsertionSort(&AET) || fixWAET) {
computeWAET(&AET);
fixWAET = FALSE;
}
}
}
FreeStorage(SLLBlock.next);
(void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
tmpPtBlock = curPtBlock->next;
g_free (curPtBlock);
curPtBlock = tmpPtBlock;
}
g_free (pETEs);
return(region);
}

View File

@ -0,0 +1,194 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
/*
* Private uninstalled header defining things local to X windowing code
*/
#ifndef __GDK_PRIVATE_FB_H__
#define __GDK_PRIVATE_FB_H__
#include <gdk/gdkprivate.h>
#include <gdk/gdk.h>
#include "gdkfb.h"
#include "gdkregion-generic.h"
#include <linux/fb.h>
#include <stdio.h>
#define GDK_DRAWABLE_FBDATA(win) ((GdkDrawableFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
#define GDK_PIXMAP_FBDATA(win) ((GdkPixmapFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
#define GDK_WINDOW_FBDATA(win) ((GdkWindowFBData *)(((GdkDrawablePrivate*)(win))->klass_data))
#define GDK_FONT_FB(f) ((GdkFontPrivateFB *)(f))
#define GDK_CURSOR_FB(c) ((GdkCursorPrivateFB *)(c))
typedef struct _GdkDrawableFBData GdkDrawableFBData;
typedef struct _GdkWindowFBData GdkWindowFBData;
struct _GdkDrawableFBData
{
guchar *mem;
gint abs_x, abs_y, lim_x, lim_y, llim_x, llim_y; /* computed values */
guint rowstride;
};
struct _GdkPixmapFBData
{
GdkDrawableFBData drawable_data;
};
typedef struct {
gulong length;
GdkAtom type;
gint format;
guchar data[1];
} GdkWindowProperty;
struct _GdkWindowFBData
{
GdkDrawableFBData drawable_data;
GdkCursor *cursor;
GHashTable *properties;
GdkEventMask event_mask;
gint level;
gboolean realized : 1;
};
struct _GdkFBDisplay
{
int fd;
guchar *fbmem;
gpointer active_cmap;
gulong mem_len;
struct fb_fix_screeninfo sinfo;
struct fb_var_screeninfo modeinfo;
};
typedef struct {
GdkVisual base;
} GdkVisualPrivateFB;
typedef struct {
GdkColormapPrivate base;
GHashTable *hash;
GdkColorInfo *info;
guint sync_tag;
} GdkColormapPrivateFB;
typedef struct {
GdkCursor base;
GdkPixmap *cursor, *mask;
} GdkCursorPrivateFB;
typedef struct {
GdkFontPrivate base;
int t1_font_id;
double size;
GSList *names;
} GdkFontPrivateFB;
typedef struct {
GdkImagePrivate base;
} GdkImagePrivateFB;
#define GDK_GC_FBDATA(x) ((GdkGCFBData *)((GdkGCPrivate *)x)->klass_data)
typedef struct {
GdkRegion *clip_region;
gchar *dash_list;
GdkGCValuesMask values_mask;
GdkGCValues values;
gint dash_offset;
gushort dash_list_len;
guchar depth, alu;
} GdkGCFBData;
GdkGC * _gdk_fb_gc_new (GdkDrawable *drawable,
GdkGCValues *values,
GdkGCValuesMask values_mask);
/* Routines from gdkgeometry-fb.c */
void _gdk_window_init_position (GdkWindow *window);
void _gdk_window_move_resize_child (GdkWindow *window,
gint x,
gint y,
gint width,
gint height);
void _gdk_window_process_expose (GdkWindow *window,
gulong serial,
GdkRectangle *area);
GdkGC *_gdk_fb_gc_new(GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask values_mask);
void gdk_fb_drawable_clear(GdkDrawable *drawable);
void gdk_fb_draw_drawable (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
void gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height,
gboolean draw_bg,
gboolean do_clipping);
void gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
void gdk_fb_fill_spans(GdkDrawable *drawable, GdkGC *gc, GdkRectangle *rects, int nrects);
extern GdkWindow *_gdk_fb_pointer_grab_window, *_gdk_fb_keyboard_grab_window, *_gdk_fb_pointer_grab_confine;
extern GdkEventMask _gdk_fb_pointer_grab_events, _gdk_fb_keyboard_grab_events;
extern GdkCursor *_gdk_fb_pointer_grab_cursor;
extern GdkFBDisplay *gdk_display;
extern GdkDrawableClass _gdk_fb_drawable_class;
extern FILE *debug_out;
GdkEvent *gdk_event_make(GdkWindow *window, GdkEventType type, gboolean append_to_queue);
void gdk_fb_get_cursor_rect(GdkRectangle *rect);
void gdk_fb_cursor_unhide(void);
void gdk_fb_cursor_hide(void);
void gdk_fb_redraw_all(void);
void gdk_input_ps2_get_mouseinfo(gint *x, gint *y, GdkModifierType *mask);
#endif /* __GDK_PRIVATE_FB_H__ */

View File

@ -0,0 +1,204 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <string.h>
#include <time.h>
#include "gdkfb.h"
#include "gdkproperty.h"
#include "gdkprivate.h"
#include "gdkprivate-fb.h"
GdkAtom
gdk_atom_intern (const gchar *atom_name,
gboolean only_if_exists)
{
g_return_val_if_fail (atom_name != NULL, GDK_NONE);
return g_quark_from_string(atom_name);
}
gchar*
gdk_atom_name (GdkAtom atom)
{
return g_quark_to_string(atom);
}
static void
gdk_property_delete_2 (GdkWindow *window,
GdkAtom property,
GdkWindowProperty *prop)
{
GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
GdkEvent *event;
g_hash_table_remove(fbd->properties, GUINT_TO_POINTER(property));
g_free(prop);
event = gdk_event_make(window, GDK_PROPERTY_NOTIFY, TRUE);
if(event)
{
event->property.atom = property;
event->property.state = GDK_PROPERTY_DELETE;
}
}
void
gdk_property_delete (GdkWindow *window,
GdkAtom property)
{
GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
GdkWindowProperty *prop;
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
if(!fbd->properties)
return;
prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
if(!prop)
return;
gdk_property_delete_2(window, property, prop);
}
gint
gdk_property_get (GdkWindow *window,
GdkAtom property,
GdkAtom type,
gulong offset,
gulong length,
gint pdelete,
GdkAtom *actual_property_type,
gint *actual_format_type,
gint *actual_length,
guchar **data)
{
GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
GdkWindowProperty *prop;
int nbytes;
g_return_val_if_fail (window != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (actual_length != NULL, FALSE);
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
if(!fbd->properties)
return FALSE;
prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
if(!prop)
return FALSE;
nbytes = (offset + length * (prop->format >> 3)) - prop->length;
nbytes = MAX(nbytes, 0);
if(nbytes > 0)
{
*data = g_malloc(nbytes+1);
memcpy(data, prop->data + offset, nbytes);
(*data)[nbytes] = 0;
}
else
*data = NULL;
*actual_length = nbytes / (prop->format >> 3);
*actual_property_type = prop->type;
*actual_format_type = prop->format;
if(pdelete)
gdk_property_delete_2(window, property, prop);
return TRUE;
}
void
gdk_property_change (GdkWindow *window,
GdkAtom property,
GdkAtom type,
gint format,
GdkPropMode mode,
const guchar *data,
gint nelements)
{
GdkWindowFBData *fbd = GDK_WINDOW_FBDATA(window);
GdkWindowProperty *prop, *new_prop;
int new_size;
GdkEvent *event;
g_return_if_fail (window != NULL);
g_return_if_fail (GDK_IS_WINDOW (window));
if(!fbd->properties)
fbd->properties = g_hash_table_new(NULL, NULL);
prop = g_hash_table_lookup(fbd->properties, GUINT_TO_POINTER(property));
switch(mode)
{
case GDK_PROP_MODE_REPLACE:
new_size = nelements * (format >> 3);
break;
case GDK_PROP_MODE_PREPEND:
case GDK_PROP_MODE_APPEND:
new_size = nelements * (format >> 3);
if(prop)
new_size += prop->length;
default:
break;
}
new_prop = g_malloc(G_STRUCT_OFFSET(GdkWindowProperty, data) + new_size);
new_prop->length = new_size;
new_prop->type = type;
new_prop->format = format;
switch(mode)
{
case GDK_PROP_MODE_REPLACE:
memcpy(new_prop->data, data, new_size);
break;
case GDK_PROP_MODE_APPEND:
if(prop)
memcpy(new_prop->data, prop->data, prop->length);
memcpy(new_prop->data + prop->length, data, (nelements * (format >> 3)));
break;
case GDK_PROP_MODE_PREPEND:
memcpy(new_prop->data, data, (nelements * (format >> 3)));
if(prop)
memcpy(new_prop->data + (nelements * (format >> 3)), prop->data, prop->length);
break;
}
g_hash_table_insert(fbd->properties, GUINT_TO_POINTER(property), new_prop);
g_free(prop);
event = gdk_event_make(window, GDK_PROPERTY_NOTIFY, TRUE);
if(event)
{
event->property.atom = property;
event->property.state = GDK_PROPERTY_NEW_VALUE;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
/* $TOG: region.h /main/9 1998/02/06 17:50:30 kaleb $ */
/************************************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
#ifndef __GDK_REGION_GENERIC_H__
#define __GDK_REGION_GENERIC_H__
typedef GdkSegment GdkRegionBox;
/*
* clip region
*/
struct _GdkRegion
{
long size;
long numRects;
GdkRegionBox *rects;
GdkRegionBox extents;
};
/* 1 if two BOXs overlap.
* 0 if two BOXs do not overlap.
* Remember, x2 and y2 are not in the region
*/
#define EXTENTCHECK(r1, r2) \
((r1)->x2 > (r2)->x1 && \
(r1)->x1 < (r2)->x2 && \
(r1)->y2 > (r2)->y1 && \
(r1)->y1 < (r2)->y2)
/*
* update region extents
*/
#define EXTENTS(r,idRect){\
if((r)->x1 < (idRect)->extents.x1)\
(idRect)->extents.x1 = (r)->x1;\
if((r)->y1 < (idRect)->extents.y1)\
(idRect)->extents.y1 = (r)->y1;\
if((r)->x2 > (idRect)->extents.x2)\
(idRect)->extents.x2 = (r)->x2;\
if((r)->y2 > (idRect)->extents.y2)\
(idRect)->extents.y2 = (r)->y2;\
}
/*
* Check to see if there is enough memory in the present region.
*/
#define MEMCHECK(reg, rect, firstrect){ \
if ((reg)->numRects >= ((reg)->size - 1)) { \
(firstrect) = g_renew (GdkRegionBox, (firstrect), 2 * (reg)->size); \
(reg)->size *= 2; \
(rect) = &(firstrect)[(reg)->numRects]; \
} \
}
/* this routine checks to see if the previous rectangle is the same
* or subsumes the new rectangle to add.
*/
#define CHECK_PREVIOUS(Reg, R, Rx1, Ry1, Rx2, Ry2)\
(!(((Reg)->numRects > 0)&&\
((R-1)->y1 == (Ry1)) &&\
((R-1)->y2 == (Ry2)) &&\
((R-1)->x1 <= (Rx1)) &&\
((R-1)->x2 >= (Rx2))))
/* add a rectangle to the given Region */
#define ADDRECT(reg, r, rx1, ry1, rx2, ry2){\
if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&\
CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
(r)->x1 = (rx1);\
(r)->y1 = (ry1);\
(r)->x2 = (rx2);\
(r)->y2 = (ry2);\
EXTENTS((r), (reg));\
(reg)->numRects++;\
(r)++;\
}\
}
/* add a rectangle to the given Region */
#define ADDRECTNOX(reg, r, rx1, ry1, rx2, ry2){\
if ((rx1 < rx2) && (ry1 < ry2) &&\
CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
(r)->x1 = (rx1);\
(r)->y1 = (ry1);\
(r)->x2 = (rx2);\
(r)->y2 = (ry2);\
(reg)->numRects++;\
(r)++;\
}\
}
#define EMPTY_REGION(pReg) pReg->numRects = 0
#define REGION_NOT_EMPTY(pReg) pReg->numRects
#define INBOX(r, x, y) \
( ( ((r).x2 > x)) && \
( ((r).x1 <= x)) && \
( ((r).y2 > y)) && \
( ((r).y1 <= y)) )
/*
* number of points to buffer before sending them off
* to scanlines() : Must be an even number
*/
#define NUMPTSTOBUFFER 200
/*
* used to allocate buffers for points and link
* the buffers together
*/
typedef struct _POINTBLOCK {
GdkPoint pts[NUMPTSTOBUFFER];
struct _POINTBLOCK *next;
} POINTBLOCK;
#endif /* __GDK_REGION_GENERIC_H__ */

View File

@ -0,0 +1,104 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <string.h>
#include "gdkproperty.h"
#include "gdkselection.h"
#include "gdkprivate.h"
#include "gdkprivate-fb.h"
gint
gdk_selection_owner_set (GdkWindow *owner,
GdkAtom selection,
guint32 time,
gint send_event)
{
return FALSE;
}
GdkWindow*
gdk_selection_owner_get (GdkAtom selection)
{
return NULL;
}
void
gdk_selection_convert (GdkWindow *requestor,
GdkAtom selection,
GdkAtom target,
guint32 time)
{
}
gint
gdk_selection_property_get (GdkWindow *requestor,
guchar **data,
GdkAtom *ret_type,
gint *ret_format)
{
g_return_val_if_fail (requestor != NULL, 0);
g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
return 0;
}
void
gdk_selection_send_notify (guint32 requestor,
GdkAtom selection,
GdkAtom target,
GdkAtom property,
guint32 time)
{
}
gint
gdk_text_property_to_text_list (GdkAtom encoding, gint format,
const guchar *text, gint length,
gchar ***list)
{
return 0;
}
void
gdk_free_text_list (gchar **list)
{
g_return_if_fail (list != NULL);
}
gint
gdk_string_to_compound_text (const gchar *str,
GdkAtom *encoding, gint *format,
guchar **ctext, gint *length)
{
return 0;
}
void gdk_free_compound_text (guchar *ctext)
{
}

180
gdk/linux-fb/gdkvisual-fb.c Normal file
View File

@ -0,0 +1,180 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "gdkvisual.h"
#include "gdkprivate-fb.h"
#include "gdkinternals.h"
#include <endian.h>
static GdkVisual *system_visual = NULL;
#ifdef G_ENABLE_DEBUG
#if 0
static const gchar* visual_names[] =
{
"static gray",
"grayscale",
"static color",
"pseudo color",
"true color",
"direct color",
};
#endif
#endif /* G_ENABLE_DEBUG */
void
gdk_visual_init (void)
{
system_visual = g_new0(GdkVisual, 1);
system_visual->depth = system_visual->bits_per_rgb = gdk_display->modeinfo.bits_per_pixel;
system_visual->byte_order = GDK_LSB_FIRST;
system_visual->colormap_size = 0;
switch(gdk_display->sinfo.visual)
{
case FB_VISUAL_PSEUDOCOLOR:
system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
system_visual->type = GDK_VISUAL_PSEUDO_COLOR;
break;
case FB_VISUAL_DIRECTCOLOR:
system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
system_visual->type = GDK_VISUAL_DIRECT_COLOR;
case FB_VISUAL_TRUECOLOR:
if(gdk_display->sinfo.visual == GDK_VISUAL_TRUE_COLOR)
system_visual->type = GDK_VISUAL_TRUE_COLOR;
system_visual->red_prec = MIN(system_visual->depth / 3, 8);
system_visual->red_shift = 0;
system_visual->red_mask = ((1 << (system_visual->red_prec + 1)) - 1) << system_visual->red_shift;
system_visual->green_shift = system_visual->red_prec;
system_visual->green_prec = MIN(system_visual->depth / 3, 8);
system_visual->green_mask = ((1 << (system_visual->green_prec + 1)) - 1) << system_visual->green_shift;
system_visual->blue_shift = system_visual->green_prec + system_visual->green_shift;
system_visual->blue_prec = MIN(system_visual->depth / 3, 8);
system_visual->blue_mask = ((1 << (system_visual->blue_prec + 1)) - 1) << system_visual->blue_shift;
break;
case FB_VISUAL_STATIC_PSEUDOCOLOR:
system_visual->type = GDK_VISUAL_STATIC_COLOR;
system_visual->colormap_size = 1 << gdk_display->modeinfo.bits_per_pixel;
break;
default:
g_assert_not_reached();
break;
}
}
GdkVisual*
gdk_visual_ref (GdkVisual *visual)
{
return visual;
}
void
gdk_visual_unref (GdkVisual *visual)
{
}
gint
gdk_visual_get_best_depth (void)
{
return system_visual->depth;
}
GdkVisualType
gdk_visual_get_best_type (void)
{
return system_visual->type;
}
GdkVisual*
gdk_visual_get_system (void)
{
return system_visual;
}
GdkVisual*
gdk_visual_get_best (void)
{
return system_visual;
}
GdkVisual*
gdk_visual_get_best_with_depth (gint depth)
{
if(system_visual->depth != depth)
return NULL;
return system_visual;
}
GdkVisual*
gdk_visual_get_best_with_type (GdkVisualType visual_type)
{
if(system_visual->type != visual_type)
return NULL;
return system_visual;
}
GdkVisual*
gdk_visual_get_best_with_both (gint depth,
GdkVisualType visual_type)
{
if(system_visual->depth != depth)
return NULL;
if(system_visual->type != visual_type)
return NULL;
return system_visual;
}
void
gdk_query_depths (gint **depths,
gint *count)
{
*count = 1;
*depths = &system_visual->depth;
}
void
gdk_query_visual_types (GdkVisualType **visual_types,
gint *count)
{
*count = 1;
*visual_types = &system_visual->type;
}
GList*
gdk_list_visuals (void)
{
return g_list_append(NULL, gdk_visual_get_system());
}

1372
gdk/linux-fb/gdkwindow-fb.c Normal file

File diff suppressed because it is too large Load Diff

21
gdk/linux-fb/mi.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef MI_H
#define MI_H 1
#include "mitypes.h"
#include "mistruct.h"
#include "mifpoly.h"
#include "mifillarc.h"
#include "mipoly.h"
void miPolyArc(GdkDrawable *pDraw, GdkGC *pGC, int narcs, miArc *parcs);
void miPolyFillArc(GdkDrawable *pDraw, GdkGC *pGC, int narcs, miArc *parcs);
void miFillPolygon(GdkDrawable *dst, GdkGC *pgc, int shape, int mode, int count, GdkPoint *pPts);
miDashPtr miDashLine(int npt, GdkPoint *ppt, unsigned int nDash, unsigned char *pDash, unsigned int offset, int *pnseg);
void miZeroLine(GdkDrawable *pDraw, GdkGC *pGC, int mode, int npt, GdkPoint *pptInit);
void miZeroDashLine(GdkDrawable *dst, GdkGC *pgc, int mode, int nptInit, GdkPoint *pptInit);
void miStepDash (int dist, int *pDashIndex, unsigned char *pDash, int numInDashList, int *pDashOffset);
void miWideDash (GdkDrawable *pDrawable, GdkGC *pGC, int mode, int npt, GdkPoint *pPts);
void miWideLine (GdkDrawable *pDrawable, GdkGC *pGC, int mode, int npt, GdkPoint *pPts);
#endif

3569
gdk/linux-fb/miarc.c Normal file

File diff suppressed because it is too large Load Diff

309
gdk/linux-fb/midash.c Normal file
View File

@ -0,0 +1,309 @@
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: midash.c /main/14 1998/02/09 14:46:34 kaleb $ */
#include "mi.h"
static miDashPtr CheckDashStorage();
/* return a list of DashRec. there will be an extra
entry at the end holding the last point of the polyline.
this means that the code that actually draws dashes can
get a pair of points for every dash. only the point in the last
dash record is useful; the other fields are not used.
nseg is the number of segments, not the number of points.
example:
dash1.start
dash2.start
dash3.start
last-point
defines a list of segments
(dash1.pt, dash2.pt)
(dash2.pt, dash3.pt)
(dash3.pt, last-point)
and nseg == 3.
NOTE:
EVEN_DASH == ~ODD_DASH
NOTE ALSO:
miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
*/
enum { EVEN_DASH=0, ODD_DASH=1 };
#define sign(x) ((x)>0)?1:( ((x)<0)?-1:0 )
miDashPtr
miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
int npt;
GdkPoint* ppt;
unsigned int nDash;
unsigned char *pDash;
unsigned int offset;
int *pnseg;
{
GdkPoint pt1, pt2;
int lenCur; /* npt used from this dash */
int lenMax; /* npt in this dash */
int iDash = 0; /* index of current dash */
int which; /* EVEN_DASH or ODD_DASH */
miDashPtr pseg; /* list of dash segments */
miDashPtr psegBase; /* start of list */
int nseg = 0; /* number of dashes so far */
int nsegMax = 0; /* num segs we can fit in this list */
int x, y, len;
int adx, ady, signdx, signdy;
int du, dv, e1, e2, e, base_e = 0;
lenCur = offset;
which = EVEN_DASH;
while(lenCur >= pDash[iDash])
{
lenCur -= pDash[iDash];
iDash++;
if (iDash >= nDash)
iDash = 0;
which = ~which;
}
lenMax = pDash[iDash];
psegBase = (miDashPtr)NULL;
pt2 = ppt[0]; /* just in case there is only one point */
while(--npt)
{
if (PtEqual(ppt[0], ppt[1]))
{
ppt++;
continue; /* no duplicated points in polyline */
}
pt1 = *ppt++;
pt2 = *ppt;
adx = pt2.x - pt1.x;
ady = pt2.y - pt1.y;
signdx = sign(adx);
signdy = sign(ady);
adx = abs(adx);
ady = abs(ady);
if (adx > ady)
{
du = adx;
dv = ady;
len = adx;
}
else
{
du = ady;
dv = adx;
len = ady;
}
e1 = dv * 2;
e2 = e1 - 2*du;
e = e1 - du;
x = pt1.x;
y = pt1.y;
nseg++;
pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
if (!pseg)
return (miDashPtr)NULL;
pseg->pt = pt1;
pseg->e1 = e1;
pseg->e2 = e2;
base_e = pseg->e = e;
pseg->which = which;
pseg->newLine = 1;
while (len--)
{
if (adx > ady)
{
/* X_AXIS */
if (((signdx > 0) && (e < 0)) ||
((signdx <=0) && (e <=0))
)
{
e += e1;
}
else
{
y += signdy;
e += e2;
}
x += signdx;
}
else
{
/* Y_AXIS */
if (((signdx > 0) && (e < 0)) ||
((signdx <=0) && (e <=0))
)
{
e +=e1;
}
else
{
x += signdx;
e += e2;
}
y += signdy;
}
lenCur++;
if (lenCur >= lenMax && (len || npt <= 1))
{
nseg++;
pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
if (!pseg)
return (miDashPtr)NULL;
pseg->pt.x = x;
pseg->pt.y = y;
pseg->e1 = e1;
pseg->e2 = e2;
pseg->e = e;
which = ~which;
pseg->which = which;
pseg->newLine = 0;
/* move on to next dash */
iDash++;
if (iDash >= nDash)
iDash = 0;
lenMax = pDash[iDash];
lenCur = 0;
}
} /* while len-- */
} /* while --npt */
if (lenCur == 0 && nseg != 0)
{
nseg--;
which = ~which;
}
*pnseg = nseg;
pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
if (!pseg)
return (miDashPtr)NULL;
pseg->pt = pt2;
pseg->e = base_e;
pseg->which = which;
pseg->newLine = 0;
return psegBase;
}
#define NSEGDELTA 16
/* returns a pointer to the pseg[nseg-1], growing the storage as
necessary. this interface seems unnecessarily cumbersome.
*/
static
miDashPtr
CheckDashStorage(ppseg, nseg, pnsegMax)
miDashPtr *ppseg; /* base pointer */
int nseg; /* number of segment we want to write to */
int *pnsegMax; /* size (in segments) of list so far */
{
if (nseg > *pnsegMax)
{
miDashPtr newppseg;
*pnsegMax += NSEGDELTA;
newppseg = (miDashPtr)g_realloc(*ppseg,
(*pnsegMax)*sizeof(miDashRec));
if (!newppseg)
{
g_free(*ppseg);
return (miDashPtr)NULL;
}
*ppseg = newppseg;
}
return(*ppseg+(nseg-1));
}
void
miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
int dist; /* distance to step */
int *pDashIndex; /* current dash */
unsigned char *pDash; /* dash list */
int numInDashList; /* total length of dash list */
int *pDashOffset; /* offset into current dash */
{
int dashIndex, dashOffset;
int totallen;
int i;
dashIndex = *pDashIndex;
dashOffset = *pDashOffset;
if (dist < pDash[dashIndex] - dashOffset)
{
*pDashOffset = dashOffset + dist;
return;
}
dist -= pDash[dashIndex] - dashOffset;
if (++dashIndex == numInDashList)
dashIndex = 0;
totallen = 0;
for (i = 0; i < numInDashList; i++)
totallen += pDash[i];
if (totallen <= dist)
dist = dist % totallen;
while (dist >= pDash[dashIndex])
{
dist -= pDash[dashIndex];
if (++dashIndex == numInDashList)
dashIndex = 0;
}
*pDashIndex = dashIndex;
*pDashOffset = dist;
}

743
gdk/linux-fb/mifillarc.c Normal file
View File

@ -0,0 +1,743 @@
/* $XFree86: xc/programs/Xserver/mi/mifillarc.c,v 3.4 1999/04/11 13:11:20 dawes Exp $ */
/************************************************************
Copyright 1989, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Author: Bob Scheifler, MIT X Consortium
********************************************************/
/* $TOG: mifillarc.c /main/20 1998/02/09 14:46:52 kaleb $ */
#include <math.h>
#include "mi.h"
#include "mifillarc.h"
#include "gdkprivate-fb.h"
#define QUADRANT (90 * 64)
#define HALFCIRCLE (180 * 64)
#define QUADRANT3 (270 * 64)
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define Dsin(d) sin((double)d*(M_PI/11520.0))
#define Dcos(d) cos((double)d*(M_PI/11520.0))
void
miFillArcSetup(arc, info)
register miArc *arc;
register miFillArcRec *info;
{
info->y = arc->height >> 1;
info->dy = arc->height & 1;
info->yorg = arc->y + info->y;
info->dx = arc->width & 1;
info->xorg = arc->x + (arc->width >> 1) + info->dx;
info->dx = 1 - info->dx;
if (arc->width == arc->height)
{
/* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
/* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
info->ym = 8;
info->xm = 8;
info->yk = info->y << 3;
if (!info->dx)
{
info->xk = 0;
info->e = -1;
}
else
{
info->y++;
info->yk += 4;
info->xk = -4;
info->e = - (info->y << 3);
}
}
else
{
/* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
/* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
info->ym = (arc->width * arc->width) << 3;
info->xm = (arc->height * arc->height) << 3;
info->yk = info->y * info->ym;
if (!info->dy)
info->yk -= info->ym >> 1;
if (!info->dx)
{
info->xk = 0;
info->e = - (info->xm >> 3);
}
else
{
info->y++;
info->yk += info->ym;
info->xk = -(info->xm >> 1);
info->e = info->xk - info->yk;
}
}
}
void
miFillArcDSetup(arc, info)
register miArc *arc;
register miFillArcDRec *info;
{
/* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
/* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
info->y = arc->height >> 1;
info->dy = arc->height & 1;
info->yorg = arc->y + info->y;
info->dx = arc->width & 1;
info->xorg = arc->x + (arc->width >> 1) + info->dx;
info->dx = 1 - info->dx;
info->ym = ((double)arc->width) * (arc->width * 8);
info->xm = ((double)arc->height) * (arc->height * 8);
info->yk = info->y * info->ym;
if (!info->dy)
info->yk -= info->ym / 2.0;
if (!info->dx)
{
info->xk = 0;
info->e = - (info->xm / 8.0);
}
else
{
info->y++;
info->yk += info->ym;
info->xk = -info->xm / 2.0;
info->e = info->xk - info->yk;
}
}
static void
miGetArcEdge(arc, edge, k, top, left)
register miArc *arc;
register miSliceEdgePtr edge;
int k;
gboolean top, left;
{
register int xady, y;
y = arc->height >> 1;
if (!(arc->width & 1))
y++;
if (!top)
{
y = -y;
if (arc->height & 1)
y--;
}
xady = k + y * edge->dx;
if (xady <= 0)
edge->x = - ((-xady) / edge->dy + 1);
else
edge->x = (xady - 1) / edge->dy;
edge->e = xady - edge->x * edge->dy;
if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
edge->e = edge->dy - edge->e + 1;
if (left)
edge->x++;
edge->x += arc->x + (arc->width >> 1);
if (edge->dx > 0)
{
edge->deltax = 1;
edge->stepx = edge->dx / edge->dy;
edge->dx = edge->dx % edge->dy;
}
else
{
edge->deltax = -1;
edge->stepx = - ((-edge->dx) / edge->dy);
edge->dx = (-edge->dx) % edge->dy;
}
if (!top)
{
edge->deltax = -edge->deltax;
edge->stepx = -edge->stepx;
}
}
void
miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp)
int angle;
int width;
int height;
int *dxp;
int *dyp;
double *d_dxp;
double *d_dyp;
{
int dx, dy;
double d_dx, d_dy, scale;
gboolean negative_dx, negative_dy;
switch (angle) {
case 0:
*dxp = -1;
*dyp = 0;
if (d_dxp) {
*d_dxp = width / 2.0;
*d_dyp = 0;
}
break;
case QUADRANT:
*dxp = 0;
*dyp = 1;
if (d_dxp) {
*d_dxp = 0;
*d_dyp = - height / 2.0;
}
break;
case HALFCIRCLE:
*dxp = 1;
*dyp = 0;
if (d_dxp) {
*d_dxp = - width / 2.0;
*d_dyp = 0;
}
break;
case QUADRANT3:
*dxp = 0;
*dyp = -1;
if (d_dxp) {
*d_dxp = 0;
*d_dyp = height / 2.0;
}
break;
default:
d_dx = Dcos(angle) * width;
d_dy = Dsin(angle) * height;
if (d_dxp) {
*d_dxp = d_dx / 2.0;
*d_dyp = - d_dy / 2.0;
}
negative_dx = FALSE;
if (d_dx < 0.0)
{
d_dx = -d_dx;
negative_dx = TRUE;
}
negative_dy = FALSE;
if (d_dy < 0.0)
{
d_dy = -d_dy;
negative_dy = TRUE;
}
scale = d_dx;
if (d_dy > d_dx)
scale = d_dy;
dx = floor ((d_dx * 32768) / scale + 0.5);
if (negative_dx)
dx = -dx;
*dxp = dx;
dy = floor ((d_dy * 32768) / scale + 0.5);
if (negative_dy)
dy = -dy;
*dyp = dy;
break;
}
}
static void
miGetPieEdge(arc, angle, edge, top, left)
register miArc *arc;
register int angle;
register miSliceEdgePtr edge;
gboolean top, left;
{
register int k;
int dx, dy;
miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
if (dy == 0)
{
edge->x = left ? -65536 : 65536;
edge->stepx = 0;
edge->e = 0;
edge->dx = -1;
return;
}
if (dx == 0)
{
edge->x = arc->x + (arc->width >> 1);
if (left && (arc->width & 1))
edge->x++;
else if (!left && !(arc->width & 1))
edge->x--;
edge->stepx = 0;
edge->e = 0;
edge->dx = -1;
return;
}
if (dy < 0) {
dx = -dx;
dy = -dy;
}
k = (arc->height & 1) ? dx : 0;
if (arc->width & 1)
k += dy;
edge->dx = dx << 1;
edge->dy = dy << 1;
miGetArcEdge(arc, edge, k, top, left);
}
void
miFillArcSliceSetup(arc, slice, pGC)
register miArc *arc;
register miArcSliceRec *slice;
GdkGC* pGC;
{
register int angle1, angle2;
angle1 = arc->angle1;
if (arc->angle2 < 0)
{
angle2 = angle1;
angle1 += arc->angle2;
}
else
angle2 = angle1 + arc->angle2;
while (angle1 < 0)
angle1 += FULLCIRCLE;
while (angle1 >= FULLCIRCLE)
angle1 -= FULLCIRCLE;
while (angle2 < 0)
angle2 += FULLCIRCLE;
while (angle2 >= FULLCIRCLE)
angle2 -= FULLCIRCLE;
slice->min_top_y = 0;
slice->max_top_y = arc->height >> 1;
slice->min_bot_y = 1 - (arc->height & 1);
slice->max_bot_y = slice->max_top_y - 1;
slice->flip_top = FALSE;
slice->flip_bot = FALSE;
if (0 /* pGC->arcMode == ArcPieSlice */)
{
slice->edge1_top = (angle1 < HALFCIRCLE);
slice->edge2_top = (angle2 <= HALFCIRCLE);
if ((angle2 == 0) || (angle1 == HALFCIRCLE))
{
if (angle2 ? slice->edge2_top : slice->edge1_top)
slice->min_top_y = slice->min_bot_y;
else
slice->min_top_y = arc->height;
slice->min_bot_y = 0;
}
else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
{
slice->min_top_y = slice->min_bot_y;
if (angle1 ? slice->edge1_top : slice->edge2_top)
slice->min_bot_y = arc->height;
else
slice->min_bot_y = 0;
}
else if (slice->edge1_top == slice->edge2_top)
{
if (angle2 < angle1)
{
slice->flip_top = slice->edge1_top;
slice->flip_bot = !slice->edge1_top;
}
else if (slice->edge1_top)
{
slice->min_top_y = 1;
slice->min_bot_y = arc->height;
}
else
{
slice->min_bot_y = 0;
slice->min_top_y = arc->height;
}
}
miGetPieEdge(arc, angle1, &slice->edge1,
slice->edge1_top, !slice->edge1_top);
miGetPieEdge(arc, angle2, &slice->edge2,
slice->edge2_top, slice->edge2_top);
}
else
{
double w2, h2, x1, y1, x2, y2, dx, dy, scale;
int signdx, signdy, y, k;
gboolean isInt1 = TRUE, isInt2 = TRUE;
w2 = (double)arc->width / 2.0;
h2 = (double)arc->height / 2.0;
if ((angle1 == 0) || (angle1 == HALFCIRCLE))
{
x1 = angle1 ? -w2 : w2;
y1 = 0.0;
}
else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
{
x1 = 0.0;
y1 = (angle1 == QUADRANT) ? h2 : -h2;
}
else
{
isInt1 = FALSE;
x1 = Dcos(angle1) * w2;
y1 = Dsin(angle1) * h2;
}
if ((angle2 == 0) || (angle2 == HALFCIRCLE))
{
x2 = angle2 ? -w2 : w2;
y2 = 0.0;
}
else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
{
x2 = 0.0;
y2 = (angle2 == QUADRANT) ? h2 : -h2;
}
else
{
isInt2 = FALSE;
x2 = Dcos(angle2) * w2;
y2 = Dsin(angle2) * h2;
}
dx = x2 - x1;
dy = y2 - y1;
if (arc->height & 1)
{
y1 -= 0.5;
y2 -= 0.5;
}
if (arc->width & 1)
{
x1 += 0.5;
x2 += 0.5;
}
if (dy < 0.0)
{
dy = -dy;
signdy = -1;
}
else
signdy = 1;
if (dx < 0.0)
{
dx = -dx;
signdx = -1;
}
else
signdx = 1;
if (isInt1 && isInt2)
{
slice->edge1.dx = dx * 2;
slice->edge1.dy = dy * 2;
}
else
{
scale = (dx > dy) ? dx : dy;
slice->edge1.dx = floor((dx * 32768) / scale + .5);
slice->edge1.dy = floor((dy * 32768) / scale + .5);
}
if (!slice->edge1.dy)
{
if (signdx < 0)
{
y = floor(y1 + 1.0);
if (y >= 0)
{
slice->min_top_y = y;
slice->min_bot_y = arc->height;
}
else
{
slice->max_bot_y = -y - (arc->height & 1);
}
}
else
{
y = floor(y1);
if (y >= 0)
slice->max_top_y = y;
else
{
slice->min_top_y = arc->height;
slice->min_bot_y = -y - (arc->height & 1);
}
}
slice->edge1_top = TRUE;
slice->edge1.x = 65536;
slice->edge1.stepx = 0;
slice->edge1.e = 0;
slice->edge1.dx = -1;
slice->edge2 = slice->edge1;
slice->edge2_top = FALSE;
}
else if (!slice->edge1.dx)
{
if (signdy < 0)
x1 -= 1.0;
slice->edge1.x = ceil(x1);
slice->edge1_top = signdy < 0;
slice->edge1.x += arc->x + (arc->width >> 1);
slice->edge1.stepx = 0;
slice->edge1.e = 0;
slice->edge1.dx = -1;
slice->edge2_top = !slice->edge1_top;
slice->edge2 = slice->edge1;
}
else
{
if (signdx < 0)
slice->edge1.dx = -slice->edge1.dx;
if (signdy < 0)
slice->edge1.dx = -slice->edge1.dx;
k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
slice->edge2.dx = slice->edge1.dx;
slice->edge2.dy = slice->edge1.dy;
slice->edge1_top = signdy < 0;
slice->edge2_top = !slice->edge1_top;
miGetArcEdge(arc, &slice->edge1, k,
slice->edge1_top, !slice->edge1_top);
miGetArcEdge(arc, &slice->edge2, k,
slice->edge2_top, slice->edge2_top);
}
}
}
#define ADDSPANS() \
pts->x = xorg - x; \
pts->y = yorg - y; \
pts->width = slw; \
pts->height = 1; \
pts++; \
if (miFillArcLower(slw)) \
{ \
pts->x = xorg - x; \
pts->y = yorg + y + dy; \
pts->width = slw; \
pts->height = 1; \
pts++; \
}
static void
miFillEllipseI(pDraw, pGC, arc)
GdkDrawable* pDraw;
GdkGC* pGC;
miArc *arc;
{
register int x, y, e;
int yk, xk, ym, xm, dx, dy, xorg, yorg;
int slw;
miFillArcRec info;
GdkRectangle* points;
register GdkRectangle* pts;
points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * arc->height);
if (!points)
return;
miFillArcSetup(arc, &info);
MIFILLARCSETUP();
pts = points;
while (y > 0)
{
MIFILLARCSTEP(slw);
ADDSPANS();
}
gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
DEALLOCATE_LOCAL(points);
}
static void
miFillEllipseD(pDraw, pGC, arc)
GdkDrawable* pDraw;
GdkGC* pGC;
miArc *arc;
{
register int x, y;
int xorg, yorg, dx, dy, slw;
double e, yk, xk, ym, xm;
miFillArcDRec info;
GdkRectangle* points;
register GdkRectangle* pts;
points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * arc->height);
if (!points)
return;
miFillArcDSetup(arc, &info);
MIFILLARCSETUP();
pts = points;
while (y > 0)
{
MIFILLARCSTEP(slw);
ADDSPANS();
}
gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
DEALLOCATE_LOCAL(points);
}
#define ADDSPAN(l,r) \
if (r >= l) \
{ \
pts->x = l; \
pts->y = ya; \
pts->width = r - l + 1; \
pts->height = 1; \
pts++; \
}
#define ADDSLICESPANS(flip) \
if (!flip) \
{ \
ADDSPAN(xl, xr); \
} \
else \
{ \
xc = xorg - x; \
ADDSPAN(xc, xr); \
xc += slw - 1; \
ADDSPAN(xl, xc); \
}
static void
miFillArcSliceI(pDraw, pGC, arc)
GdkDrawable* pDraw;
GdkGC* pGC;
miArc *arc;
{
int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
register int x, y, e;
miFillArcRec info;
miArcSliceRec slice;
int ya, xl, xr, xc;
GdkRectangle* points;
register GdkRectangle* pts;
miFillArcSetup(arc, &info);
miFillArcSliceSetup(arc, &slice, pGC);
MIFILLARCSETUP();
slw = arc->height;
if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1;
points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * slw);
if (!points)
return;
pts = points;
while (y > 0)
{
MIFILLARCSTEP(slw);
MIARCSLICESTEP(slice.edge1);
MIARCSLICESTEP(slice.edge2);
if (miFillSliceUpper(slice))
{
ya = yorg - y;
MIARCSLICEUPPER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_top);
}
if (miFillSliceLower(slice))
{
ya = yorg + y + dy;
MIARCSLICELOWER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_bot);
}
}
gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
DEALLOCATE_LOCAL(points);
}
static void
miFillArcSliceD(pDraw, pGC, arc)
GdkDrawable* pDraw;
GdkGC* pGC;
miArc *arc;
{
register int x, y;
int dx, dy, xorg, yorg, slw;
double e, yk, xk, ym, xm;
miFillArcDRec info;
miArcSliceRec slice;
int ya, xl, xr, xc;
GdkRectangle* points;
register GdkRectangle* pts;
miFillArcDSetup(arc, &info);
miFillArcSliceSetup(arc, &slice, pGC);
MIFILLARCSETUP();
slw = arc->height;
if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1;
points = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * slw);
if (!points)
return;
pts = points;
while (y > 0)
{
MIFILLARCSTEP(slw);
MIARCSLICESTEP(slice.edge1);
MIARCSLICESTEP(slice.edge2);
if (miFillSliceUpper(slice))
{
ya = yorg - y;
MIARCSLICEUPPER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_top);
}
if (miFillSliceLower(slice))
{
ya = yorg + y + dy;
MIARCSLICELOWER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_bot);
}
}
gdk_fb_fill_spans(pDraw, pGC, points, pts - points);
DEALLOCATE_LOCAL(points);
}
/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
* Since we don't have to worry about overlapping segments, we can just
* fill each arc as it comes.
*/
void
miPolyFillArc(pDraw, pGC, narcs, parcs)
GdkDrawable* pDraw;
GdkGC* pGC;
int narcs;
miArc *parcs;
{
register int i;
register miArc *arc;
for(i = narcs, arc = parcs; --i >= 0; arc++)
{
if (miFillArcEmpty(arc))
continue;;
if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
{
if (miCanFillArc(arc))
miFillEllipseI(pDraw, pGC, arc);
else
miFillEllipseD(pDraw, pGC, arc);
}
else
{
if (miCanFillArc(arc))
miFillArcSliceI(pDraw, pGC, arc);
else
miFillArcSliceD(pDraw, pGC, arc);
}
}
}

224
gdk/linux-fb/mifillarc.h Normal file
View File

@ -0,0 +1,224 @@
/* $XFree86: xc/programs/Xserver/mi/mifillarc.h,v 3.3 1998/10/04 09:39:27 dawes Exp $ */
/************************************************************
Copyright 1989, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
********************************************************/
/* $TOG: mifillarc.h /main/11 1998/02/09 14:46:57 kaleb $ */
#ifndef MIFILLARC_H
#define MIFILLARC_H 1
#define FULLCIRCLE (360 * 64)
typedef struct _miFillArc {
int xorg, yorg;
int y;
int dx, dy;
int e;
int ym, yk, xm, xk;
} miFillArcRec;
/* could use 64-bit integers */
typedef struct _miFillArcD {
int xorg, yorg;
int y;
int dx, dy;
double e;
double ym, yk, xm, xk;
} miFillArcDRec;
#define miFillArcEmpty(arc) (!(arc)->angle2 || \
!(arc)->width || !(arc)->height || \
(((arc)->width == 1) && ((arc)->height & 1)))
#define miCanFillArc(arc) (((arc)->width == (arc)->height) || \
(((arc)->width <= 800) && ((arc)->height <= 800)))
#define MIFILLARCSETUP() \
x = 0; \
y = info.y; \
e = info.e; \
xk = info.xk; \
xm = info.xm; \
yk = info.yk; \
ym = info.ym; \
dx = info.dx; \
dy = info.dy; \
xorg = info.xorg; \
yorg = info.yorg
#define MIFILLARCSTEP(slw) \
e += yk; \
while (e >= 0) \
{ \
x++; \
xk -= xm; \
e += xk; \
} \
y--; \
yk -= ym; \
slw = (x << 1) + dx; \
if ((e == xk) && (slw > 1)) \
slw--
#define MIFILLCIRCSTEP(slw) MIFILLARCSTEP(slw)
#define MIFILLELLSTEP(slw) MIFILLARCSTEP(slw)
#define miFillArcLower(slw) (((y + dy) != 0) && ((slw > 1) || (e != xk)))
typedef struct _miSliceEdge {
int x;
int stepx;
int deltax;
int e;
int dy;
int dx;
} miSliceEdgeRec, *miSliceEdgePtr;
typedef struct _miArcSlice {
miSliceEdgeRec edge1, edge2;
int min_top_y, max_top_y;
int min_bot_y, max_bot_y;
gboolean edge1_top, edge2_top;
gboolean flip_top, flip_bot;
} miArcSliceRec;
#define MIARCSLICESTEP(edge) \
edge.x -= edge.stepx; \
edge.e -= edge.dx; \
if (edge.e <= 0) \
{ \
edge.x -= edge.deltax; \
edge.e += edge.dy; \
}
#define miFillSliceUpper(slice) \
((y >= slice.min_top_y) && (y <= slice.max_top_y))
#define miFillSliceLower(slice) \
((y >= slice.min_bot_y) && (y <= slice.max_bot_y))
#define MIARCSLICEUPPER(xl,xr,slice,slw) \
xl = xorg - x; \
xr = xl + slw - 1; \
if (slice.edge1_top && (slice.edge1.x < xr)) \
xr = slice.edge1.x; \
if (slice.edge2_top && (slice.edge2.x > xl)) \
xl = slice.edge2.x;
#define MIARCSLICELOWER(xl,xr,slice,slw) \
xl = xorg - x; \
xr = xl + slw - 1; \
if (!slice.edge1_top && (slice.edge1.x > xl)) \
xl = slice.edge1.x; \
if (!slice.edge2_top && (slice.edge2.x < xr)) \
xr = slice.edge2.x;
#define MIWIDEARCSETUP(x,y,dy,slw,e,xk,xm,yk,ym) \
x = 0; \
y = slw >> 1; \
yk = y << 3; \
xm = 8; \
ym = 8; \
if (dy) \
{ \
xk = 0; \
if (slw & 1) \
e = -1; \
else \
e = -(y << 2) - 2; \
} \
else \
{ \
y++; \
yk += 4; \
xk = -4; \
if (slw & 1) \
e = -(y << 2) - 3; \
else \
e = - (y << 3); \
}
#define MIFILLINARCSTEP(slw) \
ine += inyk; \
while (ine >= 0) \
{ \
inx++; \
inxk -= inxm; \
ine += inxk; \
} \
iny--; \
inyk -= inym; \
slw = (inx << 1) + dx; \
if ((ine == inxk) && (slw > 1)) \
slw--
#define miFillInArcLower(slw) (((iny + dy) != 0) && \
((slw > 1) || (ine != inxk)))
extern int miFreeArcCache(
#if NeedFunctionPrototypes
gpointer /*data*/,
guint /*id*/
#endif
);
extern struct finalSpan *realAllocSpan(
#if NeedFunctionPrototypes
void
#endif
);
extern void miFillArcSetup(
#if NeedFunctionPrototypes
miArc * /*arc*/,
miFillArcRec * /*info*/
#endif
);
extern void miFillArcDSetup(
#if NeedFunctionPrototypes
miArc * /*arc*/,
miFillArcDRec * /*info*/
#endif
);
extern void miEllipseAngleToSlope(
#if NeedFunctionPrototypes
int /*angle*/,
int /*width*/,
int /*height*/,
int * /*dxp*/,
int * /*dyp*/,
double * /*d_dxp*/,
double * /*d_dyp*/
#endif
);
extern void miFillArcSliceSetup(
#if NeedFunctionPrototypes
miArc * /*arc*/,
miArcSliceRec * /*slice*/,
GdkGC* /*pGC*/
#endif
);
#endif

112
gdk/linux-fb/mifpoly.h Normal file
View File

@ -0,0 +1,112 @@
/* $TOG: mifpoly.h /main/10 1998/02/09 14:47:09 kaleb $ */
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#ifndef MIFPOLY_H
#define MIFPOLY_H 1
#define EPSILON 0.000001
#define ISEQUAL(a,b) (fabs((a) - (b)) <= EPSILON)
#define UNEQUAL(a,b) (fabs((a) - (b)) > EPSILON)
#define WITHINHALF(a, b) (((a) - (b) > 0.0) ? (a) - (b) < 0.5 : \
(b) - (a) <= 0.5)
#define ROUNDTOINT(x) ((int) (((x) > 0.0) ? ((x) + 0.5) : ((x) - 0.5)))
#define ISZERO(x) (fabs((x)) <= EPSILON)
#define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y))
#define PTUNEQUAL(a,b) (UNEQUAL(a.x,b.x) || UNEQUAL(a.y,b.y))
#define PtEqual(a, b) (((a).x == (b).x) && ((a).y == (b).y))
#define NotEnd 0
#define FirstEnd 1
#define SecondEnd 2
#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - for 11o miter cutoff */
#define D2SECANT 5.21671526231167 /* 1/2*sin(11/2) - max extension per width */
#ifndef ICIEL
#ifdef NOINLINEICEIL
#define ICEIL(x) ((int)ceil(x))
#else
#ifdef __GNUC__
#define ICEIL ICIEL
static __inline int ICEIL(x)
double x;
{
int _cTmp = x;
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1;
}
#else
#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1)
#define ICEILTEMPDECL static int _cTmp;
#endif
#endif
#endif
/* Point with sub-pixel positioning. In this case we use doubles, but
* see mifpolycon.c for other suggestions
*/
typedef struct _SppPoint {
double x, y;
} SppPointRec, *SppPointPtr;
typedef struct _SppArc {
double x, y, width, height;
double angle1, angle2;
} SppArcRec, *SppArcPtr;
/* mifpolycon.c */
extern void miFillSppPoly(
#if NeedFunctionPrototypes
GdkDrawable* /*dst*/,
GdkGC* /*pgc*/,
int /*count*/,
SppPointPtr /*ptsIn*/,
int /*xTrans*/,
int /*yTrans*/,
double /*xFtrans*/,
double /*yFtrans*/
#endif
);
#endif /* MIFPOLY_H */

261
gdk/linux-fb/mifpolycon.c Normal file
View File

@ -0,0 +1,261 @@
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mifpolycon.c /main/13 1998/02/09 14:47:05 kaleb $ */
#include <math.h>
#include "mi.h"
#include "mifpoly.h"
static int GetFPolyYBounds();
#ifdef ICEILTEMPDECL
ICEILTEMPDECL
#endif
/*
* Written by Todd Newman; April. 1987.
*
* Fill a convex polygon. If the given polygon
* is not convex, then the result is undefined.
* The algorithm is to order the edges from smallest
* y to largest by partitioning the array into a left
* edge list and a right edge list. The algorithm used
* to traverse each edge is digital differencing analyzer
* line algorithm with y as the major axis. There's some funny linear
* interpolation involved because of the subpixel postioning.
*/
void
miFillSppPoly(GdkDrawable *dst, GdkGC *pgc, int count, SppPointPtr ptsIn, int xTrans, int yTrans, double xFtrans, double yFtrans)
#if 0
GdkDrawable* dst;
GdkGC* pgc;
int count; /* number of points */
SppPointPtr ptsIn; /* the points */
int xTrans, yTrans; /* Translate each point by this */
double xFtrans, yFtrans; /* translate before conversion
by this amount. This provides
a mechanism to match rounding
errors with any shape that must
meet the polygon exactly.
*/
#endif
{
double xl, xr, /* x vals of left and right edges */
ml, /* left edge slope */
mr, /* right edge slope */
dy, /* delta y */
i; /* loop counter */
int y, /* current scanline */
j,
imin, /* index of vertex with smallest y */
ymin, /* y-extents of polygon */
ymax,
*Marked; /* set if this vertex has been used */
register int left, right, /* indices to first endpoints */
nextleft,
nextright; /* indices to second endpoints */
GdkRectangle* ptsOut,
*FirstPoint; /* output buffer */
imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);
y = ymax - ymin + 1;
if ((count < 3) || (y <= 0))
return;
ptsOut = FirstPoint = (GdkRectangle*)ALLOCATE_LOCAL(sizeof(GdkRectangle) * y);
Marked = (int *) ALLOCATE_LOCAL(sizeof(int) * count);
if(!ptsOut || !Marked)
{
if (Marked) DEALLOCATE_LOCAL(Marked);
if (ptsOut) DEALLOCATE_LOCAL(ptsOut);
return;
}
for(j = 0; j < count; j++)
Marked[j] = 0;
nextleft = nextright = imin;
Marked[imin] = -1;
y = ICEIL(ptsIn[nextleft].y + yFtrans);
/*
* loop through all edges of the polygon
*/
do
{
/* add a left edge if we need to */
if ((y > (ptsIn[nextleft].y + yFtrans) ||
ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
Marked[nextleft] != 1)
{
Marked[nextleft]++;
left = nextleft++;
/* find the next edge, considering the end conditions */
if (nextleft >= count)
nextleft = 0;
/* now compute the starting point and slope */
dy = ptsIn[nextleft].y - ptsIn[left].y;
if (dy != 0.0)
{
ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
dy = y - (ptsIn[left].y + yFtrans);
xl = (ptsIn[left].x + xFtrans) + ml * MAX(dy, 0);
}
}
/* add a right edge if we need to */
if ((y > ptsIn[nextright].y + yFtrans) ||
(ISEQUAL(y, ptsIn[nextright].y + yFtrans)
&& Marked[nextright] != 1))
{
Marked[nextright]++;
right = nextright--;
/* find the next edge, considering the end conditions */
if (nextright < 0)
nextright = count - 1;
/* now compute the starting point and slope */
dy = ptsIn[nextright].y - ptsIn[right].y;
if (dy != 0.0)
{
mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
dy = y - (ptsIn[right].y + yFtrans);
xr = (ptsIn[right].x + xFtrans) + mr * MAX(dy, 0);
}
}
/*
* generate scans to fill while we still have
* a right edge as well as a left edge.
*/
i = (MIN(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;
if (i < EPSILON)
{
if(Marked[nextleft] && Marked[nextright])
{
/* Arrgh, we're trapped! (no more points)
* Out, we've got to get out of here before this decadence saps
* our will completely! */
break;
}
continue;
}
else
{
j = (int) i;
if(!j)
j++;
}
while (j > 0)
{
int cxl, cxr;
ptsOut->y = (y) + yTrans;
cxl = ICEIL(xl);
cxr = ICEIL(xr);
ptsOut->height = 1;
/* reverse the edges if necessary */
if (xl < xr)
{
ptsOut->width = cxr - cxl;
(ptsOut++)->x = cxl + xTrans;
}
else
{
ptsOut->width = cxl - cxr;
(ptsOut++)->x = cxr + xTrans;
}
y++;
/* increment down the edges */
xl += ml;
xr += mr;
j--;
}
} while (y <= ymax);
/* Finally, fill the spans we've collected */
gdk_fb_fill_spans(dst, pgc, FirstPoint, ptsOut-FirstPoint);
DEALLOCATE_LOCAL(Marked);
DEALLOCATE_LOCAL(FirstPoint);
}
/* Find the index of the point with the smallest y.also return the
* smallest and largest y */
static
int
GetFPolyYBounds(pts, n, yFtrans, by, ty)
register SppPointPtr pts;
int n;
double yFtrans;
int *by, *ty;
{
register SppPointPtr ptMin;
double ymin, ymax;
SppPointPtr ptsStart = pts;
ptMin = pts;
ymin = ymax = (pts++)->y;
while (--n > 0) {
if (pts->y < ymin)
{
ptMin = pts;
ymin = pts->y;
}
if(pts->y > ymax)
ymax = pts->y;
pts++;
}
*by = ICEIL(ymin + yFtrans);
*ty = ICEIL(ymax + yFtrans - 1);
return(ptMin-ptsStart);
}

177
gdk/linux-fb/miline.h Normal file
View File

@ -0,0 +1,177 @@
/* $TOG: miline.h /main/7 1998/02/09 14:47:30 kaleb $ */
/*
Copyright 1994, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/* $XFree86: xc/programs/Xserver/mi/miline.h,v 1.4 1999/10/13 22:33:11 dawes Exp $ */
#ifndef MILINE_H
/*
* Public definitions used for configuring basic pixelization aspects
* of the sample implementation line-drawing routines provided in
* {mfb,mi,cfb*} at run-time.
*/
#define XDECREASING 4
#define YDECREASING 2
#define YMAJOR 1
#define OCTANT1 (1 << (YDECREASING))
#define OCTANT2 (1 << (YDECREASING|YMAJOR))
#define OCTANT3 (1 << (XDECREASING|YDECREASING|YMAJOR))
#define OCTANT4 (1 << (XDECREASING|YDECREASING))
#define OCTANT5 (1 << (XDECREASING))
#define OCTANT6 (1 << (XDECREASING|YMAJOR))
#define OCTANT7 (1 << (YMAJOR))
#define OCTANT8 (1 << (0))
#define XMAJOROCTANTS (OCTANT1 | OCTANT4 | OCTANT5 | OCTANT8)
#define DEFAULTZEROLINEBIAS (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5)
/*
* Devices can configure the rendering of routines in mi, mfb, and cfb*
* by specifying a thin line bias to be applied to a particular screen
* using the following function. The bias parameter is an OR'ing of
* the appropriate OCTANT constants defined above to indicate which
* octants to bias a line to prefer an axial step when the Bresenham
* error term is exactly zero. The octants are mapped as follows:
*
* \ | /
* \ 3 | 2 /
* \ | /
* 4 \ | / 1
* \|/
* -----------
* /|\
* 5 / | \ 8
* / | \
* / 6 | 7 \
* / | \
*
* For more information, see "Ambiguities in Incremental Line Rastering,"
* Jack E. Bresenham, IEEE CG&A, May 1987.
*/
#if 0
extern void miSetZeroLineBias(
#if NeedFunctionPrototypes
ScreenPtr /* pScreen */,
unsigned int /* bias */
#endif
);
#endif
/*
* Private definitions needed for drawing thin (zero width) lines
* Used by the mi, mfb, and all cfb* components.
*/
#define X_AXIS 0
#define Y_AXIS 1
#define OUT_LEFT 0x08
#define OUT_RIGHT 0x04
#define OUT_ABOVE 0x02
#define OUT_BELOW 0x01
#define OUTCODES(_result, _x, _y, _pbox) \
if ( (_x) < (_pbox)->x1) (_result) |= OUT_LEFT; \
else if ( (_x) >= (_pbox)->x2) (_result) |= OUT_RIGHT; \
if ( (_y) < (_pbox)->y1) (_result) |= OUT_ABOVE; \
else if ( (_y) >= (_pbox)->y2) (_result) |= OUT_BELOW;
#define MIOUTCODES(outcode, x, y, xmin, ymin, xmax, ymax) \
{\
if (x < xmin) outcode |= OUT_LEFT;\
if (x > xmax) outcode |= OUT_RIGHT;\
if (y < ymin) outcode |= OUT_ABOVE;\
if (y > ymax) outcode |= OUT_BELOW;\
}
#define SWAPINT(i, j) \
{ register int _t = i; i = j; j = _t; }
#define SWAPPT(i, j) \
{ GdkPoint _t; _t = i; i = j; j = _t; }
#define SWAPINT_PAIR(x1, y1, x2, y2)\
{ int t = x1; x1 = x2; x2 = t;\
t = y1; y1 = y2; y2 = t;\
}
#if 0
#define miGetZeroLineBias(_pScreen) \
((miZeroLineScreenIndex < 0) ? \
0 : ((_pScreen)->devPrivates[miZeroLineScreenIndex].uval))
#endif
#define miGetZeroLineBias() DEFAULTZEROLINEBIAS
#define CalcLineDeltas(_x1,_y1,_x2,_y2,_adx,_ady,_sx,_sy,_SX,_SY,_octant) \
(_octant) = 0; \
(_sx) = (_SX); \
if (((_adx) = (_x2) - (_x1)) < 0) { \
(_adx) = -(_adx); \
(_sx = -(_sx)); \
(_octant) |= XDECREASING; \
} \
(_sy) = (_SY); \
if (((_ady) = (_y2) - (_y1)) < 0) { \
(_ady) = -(_ady); \
(_sy = -(_sy)); \
(_octant) |= YDECREASING; \
}
#define SetYMajorOctant(_octant) ((_octant) |= YMAJOR)
#define FIXUP_ERROR(_e, _octant, _bias) \
(_e) -= (((_bias) >> (_octant)) & 1)
#define IsXMajorOctant(_octant) (!((_octant) & YMAJOR))
#define IsYMajorOctant(_octant) ((_octant) & YMAJOR)
#define IsXDecreasingOctant(_octant) ((_octant) & XDECREASING)
#define IsYDecreasingOctant(_octant) ((_octant) & YDECREASING)
extern int miZeroLineScreenIndex;
extern int miZeroClipLine(
#if NeedFunctionPrototypes
int /*xmin*/,
int /*ymin*/,
int /*xmax*/,
int /*ymax*/,
int * /*new_x1*/,
int * /*new_y1*/,
int * /*new_x2*/,
int * /*new_y2*/,
unsigned int /*adx*/,
unsigned int /*ady*/,
int * /*pt1_clipped*/,
int * /*pt2_clipped*/,
int /*octant*/,
unsigned int /*bias*/,
int /*oc1*/,
int /*oc2*/
#endif
);
#endif /* MILINE_H */

77
gdk/linux-fb/mipoly.c Normal file
View File

@ -0,0 +1,77 @@
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mipoly.c /main/5 1998/02/09 14:48:16 kaleb $ */
/*
* mipoly.c
*
* Written by Brian Kelleher; June 1986
*
* Draw polygons. This routine translates the point by the
* origin if pGC->miTranslate is non-zero, and calls
* to the appropriate routine to actually scan convert the
* polygon.
*/
#include "mi.h"
extern gboolean miFillGeneralPoly(
#if NeedFunctionPrototypes
GdkDrawable* /*dst*/,
GdkGC* /*pgc*/,
int /*count*/,
GdkPoint* /*ptsIn*/
#endif
);
void
miFillPolygon(dst, pgc, shape, mode, count, pPts)
GdkDrawable* dst;
register GdkGC* pgc;
int shape, mode;
register int count;
GdkPoint* pPts;
{
if (count == 0)
return;
miFillGeneralPoly(dst, pgc, count, pPts);
}

230
gdk/linux-fb/mipoly.h Normal file
View File

@ -0,0 +1,230 @@
/* $TOG: mipoly.h /main/6 1998/02/09 14:48:20 kaleb $ */
/*
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
#ifndef MIPOLY_H
#define MIPOLY_H
#include "miscanfill.h"
/*
* fill.h
*
* Created by Brian Kelleher; Oct 1985
*
* Include file for filled polygon routines.
*
* These are the data structures needed to scan
* convert regions. Two different scan conversion
* methods are available -- the even-odd method, and
* the winding number method.
* The even-odd rule states that a point is inside
* the polygon if a ray drawn from that point in any
* direction will pass through an odd number of
* path segments.
* By the winding number rule, a point is decided
* to be inside the polygon if a ray drawn from that
* point in any direction passes through a different
* number of clockwise and counter-clockwise path
* segments.
*
* These data structures are adapted somewhat from
* the algorithm in (Foley/Van Dam) for scan converting
* polygons.
* The basic algorithm is to start at the top (smallest y)
* of the polygon, stepping down to the bottom of
* the polygon by incrementing the y coordinate. We
* keep a list of edges which the current scanline crosses,
* sorted by x. This list is called the Active Edge Table (AET)
* As we change the y-coordinate, we update each entry in
* in the active edge table to reflect the edges new xcoord.
* This list must be sorted at each scanline in case
* two edges intersect.
* We also keep a data structure known as the Edge Table (ET),
* which keeps track of all the edges which the current
* scanline has not yet reached. The ET is basically a
* list of ScanLineList structures containing a list of
* edges which are entered at a given scanline. There is one
* ScanLineList per scanline at which an edge is entered.
* When we enter a new edge, we move it from the ET to the AET.
*
* From the AET, we can implement the even-odd rule as in
* (Foley/Van Dam).
* The winding number rule is a little trickier. We also
* keep the EdgeTableEntries in the AET linked by the
* nextWETE (winding EdgeTableEntry) link. This allows
* the edges to be linked just as before for updating
* purposes, but only uses the edges linked by the nextWETE
* link as edges representing spans of the polygon to
* drawn (as with the even-odd rule).
*/
/*
* for the winding number rule
*/
#define CLOCKWISE 1
#define COUNTERCLOCKWISE -1
typedef struct _EdgeTableEntry {
int ymax; /* ycoord at which we exit this edge. */
BRESINFO bres; /* Bresenham info to run the edge */
struct _EdgeTableEntry *next; /* next in the list */
struct _EdgeTableEntry *back; /* for insertion sort */
struct _EdgeTableEntry *nextWETE; /* for winding num rule */
int ClockWise; /* flag for winding number rule */
} EdgeTableEntry;
typedef struct _ScanLineList{
int scanline; /* the scanline represented */
EdgeTableEntry *edgelist; /* header node */
struct _ScanLineList *next; /* next in the list */
} ScanLineList;
typedef struct {
int ymax; /* ymax for the polygon */
int ymin; /* ymin for the polygon */
ScanLineList scanlines; /* header node */
} EdgeTable;
/*
* Here is a struct to help with storage allocation
* so we can allocate a big chunk at a time, and then take
* pieces from this heap when we need to.
*/
#define SLLSPERBLOCK 25
typedef struct _ScanLineListBlock {
ScanLineList SLLs[SLLSPERBLOCK];
struct _ScanLineListBlock *next;
} ScanLineListBlock;
/*
* number of points to buffer before sending them off
* to scanlines() : Must be an even number
*/
#define NUMPTSTOBUFFER 200
/*
*
* a few macros for the inner loops of the fill code where
* performance considerations don't allow a procedure call.
*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The winding number rule is in effect, so we must notify
* the caller when the edge has been removed so he
* can reorder the Winding Active Edge Table.
*/
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
fixWAET = 1; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}
/*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The even-odd rule is in effect.
*/
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}
/* mipolyutil.c */
extern gboolean miInsertEdgeInET(
#if NeedFunctionPrototypes
EdgeTable * /*ET*/,
EdgeTableEntry * /*ETE*/,
int /*scanline*/,
ScanLineListBlock ** /*SLLBlock*/,
int * /*iSLLBlock*/
#endif
);
extern gboolean miCreateETandAET(
#if NeedFunctionPrototypes
int /*count*/,
GdkPoint* /*pts*/,
EdgeTable * /*ET*/,
EdgeTableEntry * /*AET*/,
EdgeTableEntry * /*pETEs*/,
ScanLineListBlock * /*pSLLBlock*/
#endif
);
extern void miloadAET(
#if NeedFunctionPrototypes
EdgeTableEntry * /*AET*/,
EdgeTableEntry * /*ETEs*/
#endif
);
extern void micomputeWAET(
#if NeedFunctionPrototypes
EdgeTableEntry * /*AET*/
#endif
);
extern int miInsertionSort(
#if NeedFunctionPrototypes
EdgeTableEntry * /*AET*/
#endif
);
extern void miFreeStorage(
#if NeedFunctionPrototypes
ScanLineListBlock * /*pSLLBlock*/
#endif
);
#endif

214
gdk/linux-fb/mipolygen.c Normal file
View File

@ -0,0 +1,214 @@
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mipolygen.c /main/9 1998/02/09 14:47:51 kaleb $ */
#include "mi.h"
#include "mipoly.h"
/*
*
* Written by Brian Kelleher; Oct. 1985
*
* Routine to fill a polygon. Two fill rules are
* supported: frWINDING and frEVENODD.
*
* See fillpoly.h for a complete description of the algorithm.
*/
gboolean
miFillGeneralPoly(dst, pgc, count, ptsIn)
GdkDrawable* dst;
GdkGC* pgc;
int count; /* number of points */
GdkPoint* ptsIn; /* the points */
{
register EdgeTableEntry *pAET; /* the Active Edge Table */
register int y; /* the current scanline */
register int nPts = 0; /* number of pts in buffer */
register EdgeTableEntry *pWETE; /* Winding Edge Table */
register ScanLineList *pSLL; /* Current ScanLineList */
register GdkRectangle* ptsOut; /* ptr to output buffers */
GdkRectangle FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
EdgeTableEntry *pPrevAET; /* previous AET entry */
EdgeTable ET; /* Edge Table header node */
EdgeTableEntry AET; /* Active ET header node */
EdgeTableEntry *pETEs; /* Edge Table Entries buff */
ScanLineListBlock SLLBlock; /* header for ScanLineList */
int fixWAET = 0;
if (count < 3)
return(TRUE);
if(!(pETEs = (EdgeTableEntry *)
ALLOCATE_LOCAL(sizeof(EdgeTableEntry) * count)))
return(FALSE);
ptsOut = FirstPoint;
if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock))
{
DEALLOCATE_LOCAL(pETEs);
return(FALSE);
}
pSLL = ET.scanlines.next;
if (0 /* pgc->fillRule == EvenOddRule */)
{
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++)
{
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL && y == pSLL->scanline)
{
miloadAET(&AET, pSLL->edgelist);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
/*
* for each active edge
*/
while (pAET)
{
ptsOut->x = pAET->bres.minor;
ptsOut->width = pAET->next->bres.minor - pAET->bres.minor;
ptsOut->height = 1;
ptsOut++->y = y;
nPts++;
/*
* send out the buffer when its full
*/
if (nPts == NUMPTSTOBUFFER)
{
gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
ptsOut = FirstPoint;
nPts = 0;
}
EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
}
miInsertionSort(&AET);
}
}
else /* default to WindingNumber */
{
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++)
{
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL && y == pSLL->scanline)
{
miloadAET(&AET, pSLL->edgelist);
micomputeWAET(&AET);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
pWETE = pAET;
/*
* for each active edge
*/
while (pAET)
{
/*
* if the next edge in the active edge table is
* also the next edge in the winding active edge
* table.
*/
if (pWETE == pAET)
{
ptsOut->x = pAET->bres.minor;
ptsOut->width = pAET->nextWETE->bres.minor - pAET->bres.minor;
ptsOut->height = 1;
ptsOut++->y = y;
nPts++;
/*
* send out the buffer
*/
if (nPts == NUMPTSTOBUFFER)
{
gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
ptsOut = FirstPoint;
nPts = 0;
}
pWETE = pWETE->nextWETE;
while (pWETE != pAET)
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
pWETE = pWETE->nextWETE;
}
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
}
/*
* reevaluate the Winding active edge table if we
* just had to resort it or if we just exited an edge.
*/
if (miInsertionSort(&AET) || fixWAET)
{
micomputeWAET(&AET);
fixWAET = 0;
}
}
}
/*
* Get any spans that we missed by buffering
*/
if(nPts > 0)
gdk_fb_fill_spans(dst, pgc, FirstPoint, nPts);
DEALLOCATE_LOCAL(pETEs);
miFreeStorage(SLLBlock.next);
return(TRUE);
}

392
gdk/linux-fb/mipolyutil.c Normal file
View File

@ -0,0 +1,392 @@
/* $XFree86: xc/programs/Xserver/mi/mipolyutil.c,v 1.7 1998/10/04 09:39:31 dawes Exp $ */
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mipolyutil.c /main/6 1998/02/09 14:48:12 kaleb $ */
#include <limits.h>
#include "mi.h"
#include "miscanfill.h"
#include "mipoly.h"
/*
* fillUtils.c
*
* Written by Brian Kelleher; Oct. 1985
*
* This module contains all of the utility functions
* needed to scan convert a polygon.
*
*/
/*
* InsertEdgeInET
*
* Insert the given edge into the edge table.
* First we must find the correct bucket in the
* Edge table, then find the right slot in the
* bucket. Finally, we can insert it.
*
*/
gboolean
miInsertEdgeInET(ET, ETE, scanline, SLLBlock, iSLLBlock)
EdgeTable *ET;
EdgeTableEntry *ETE;
int scanline;
ScanLineListBlock **SLLBlock;
int *iSLLBlock;
{
register EdgeTableEntry *start, *prev;
register ScanLineList *pSLL, *pPrevSLL;
ScanLineListBlock *tmpSLLBlock;
/*
* find the right bucket to put the edge into
*/
pPrevSLL = &ET->scanlines;
pSLL = pPrevSLL->next;
while (pSLL && (pSLL->scanline < scanline))
{
pPrevSLL = pSLL;
pSLL = pSLL->next;
}
/*
* reassign pSLL (pointer to ScanLineList) if necessary
*/
if ((!pSLL) || (pSLL->scanline > scanline))
{
if (*iSLLBlock > SLLSPERBLOCK-1)
{
tmpSLLBlock =
(ScanLineListBlock *)g_malloc(sizeof(ScanLineListBlock));
if (!tmpSLLBlock)
return FALSE;
(*SLLBlock)->next = tmpSLLBlock;
tmpSLLBlock->next = (ScanLineListBlock *)NULL;
*SLLBlock = tmpSLLBlock;
*iSLLBlock = 0;
}
pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
pSLL->next = pPrevSLL->next;
pSLL->edgelist = (EdgeTableEntry *)NULL;
pPrevSLL->next = pSLL;
}
pSLL->scanline = scanline;
/*
* now insert the edge in the right bucket
*/
prev = (EdgeTableEntry *)NULL;
start = pSLL->edgelist;
while (start && (start->bres.minor < ETE->bres.minor))
{
prev = start;
start = start->next;
}
ETE->next = start;
if (prev)
prev->next = ETE;
else
pSLL->edgelist = ETE;
return TRUE;
}
/*
* CreateEdgeTable
*
* This routine creates the edge table for
* scan converting polygons.
* The Edge Table (ET) looks like:
*
* EdgeTable
* --------
* | ymax | ScanLineLists
* |scanline|-->------------>-------------->...
* -------- |scanline| |scanline|
* |edgelist| |edgelist|
* --------- ---------
* | |
* | |
* V V
* list of ETEs list of ETEs
*
* where ETE is an EdgeTableEntry data structure,
* and there is one ScanLineList per scanline at
* which an edge is initially entered.
*
*/
gboolean
miCreateETandAET(count, pts, ET, AET, pETEs, pSLLBlock)
register int count;
register GdkPoint* pts;
EdgeTable *ET;
EdgeTableEntry *AET;
register EdgeTableEntry *pETEs;
ScanLineListBlock *pSLLBlock;
{
register GdkPoint* top, *bottom;
register GdkPoint* PrevPt, *CurrPt;
int iSLLBlock = 0;
int dy;
if (count < 2) return TRUE;
/*
* initialize the Active Edge Table
*/
AET->next = (EdgeTableEntry *)NULL;
AET->back = (EdgeTableEntry *)NULL;
AET->nextWETE = (EdgeTableEntry *)NULL;
AET->bres.minor = INT_MIN;
/*
* initialize the Edge Table.
*/
ET->scanlines.next = (ScanLineList *)NULL;
ET->ymax = INT_MIN;
ET->ymin = INT_MAX;
pSLLBlock->next = (ScanLineListBlock *)NULL;
PrevPt = &pts[count-1];
/*
* for each vertex in the array of points.
* In this loop we are dealing with two vertices at
* a time -- these make up one edge of the polygon.
*/
while (count--)
{
CurrPt = pts++;
/*
* find out which point is above and which is below.
*/
if (PrevPt->y > CurrPt->y)
{
bottom = PrevPt, top = CurrPt;
pETEs->ClockWise = 0;
}
else
{
bottom = CurrPt, top = PrevPt;
pETEs->ClockWise = 1;
}
/*
* don't add horizontal edges to the Edge table.
*/
if (bottom->y != top->y)
{
pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
/*
* initialize integer edge algorithm
*/
dy = bottom->y - top->y;
BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
{
miFreeStorage(pSLLBlock->next);
return FALSE;
}
ET->ymax = MAX(ET->ymax, PrevPt->y);
ET->ymin = MIN(ET->ymin, PrevPt->y);
pETEs++;
}
PrevPt = CurrPt;
}
return TRUE;
}
/*
* loadAET
*
* This routine moves EdgeTableEntries from the
* EdgeTable into the Active Edge Table,
* leaving them sorted by smaller x coordinate.
*
*/
void
miloadAET(AET, ETEs)
register EdgeTableEntry *AET, *ETEs;
{
register EdgeTableEntry *pPrevAET;
register EdgeTableEntry *tmp;
pPrevAET = AET;
AET = AET->next;
while (ETEs)
{
while (AET && (AET->bres.minor < ETEs->bres.minor))
{
pPrevAET = AET;
AET = AET->next;
}
tmp = ETEs->next;
ETEs->next = AET;
if (AET)
AET->back = ETEs;
ETEs->back = pPrevAET;
pPrevAET->next = ETEs;
pPrevAET = ETEs;
ETEs = tmp;
}
}
/*
* computeWAET
*
* This routine links the AET by the
* nextWETE (winding EdgeTableEntry) link for
* use by the winding number rule. The final
* Active Edge Table (AET) might look something
* like:
*
* AET
* ---------- --------- ---------
* |ymax | |ymax | |ymax |
* | ... | |... | |... |
* |next |->|next |->|next |->...
* |nextWETE| |nextWETE| |nextWETE|
* --------- --------- ^--------
* | | |
* V-------------------> V---> ...
*
*/
void
micomputeWAET(AET)
register EdgeTableEntry *AET;
{
register EdgeTableEntry *pWETE;
register int inside = 1;
register int isInside = 0;
AET->nextWETE = (EdgeTableEntry *)NULL;
pWETE = AET;
AET = AET->next;
while (AET)
{
if (AET->ClockWise)
isInside++;
else
isInside--;
if ((!inside && !isInside) ||
( inside && isInside))
{
pWETE->nextWETE = AET;
pWETE = AET;
inside = !inside;
}
AET = AET->next;
}
pWETE->nextWETE = (EdgeTableEntry *)NULL;
}
/*
* InsertionSort
*
* Just a simple insertion sort using
* pointers and back pointers to sort the Active
* Edge Table.
*
*/
int
miInsertionSort(AET)
register EdgeTableEntry *AET;
{
register EdgeTableEntry *pETEchase;
register EdgeTableEntry *pETEinsert;
register EdgeTableEntry *pETEchaseBackTMP;
register int changed = 0;
AET = AET->next;
while (AET)
{
pETEinsert = AET;
pETEchase = AET;
while (pETEchase->back->bres.minor > AET->bres.minor)
pETEchase = pETEchase->back;
AET = AET->next;
if (pETEchase != pETEinsert)
{
pETEchaseBackTMP = pETEchase->back;
pETEinsert->back->next = AET;
if (AET)
AET->back = pETEinsert->back;
pETEinsert->next = pETEchase;
pETEchase->back->next = pETEinsert;
pETEchase->back = pETEinsert;
pETEinsert->back = pETEchaseBackTMP;
changed = 1;
}
}
return(changed);
}
/*
* Clean up our act.
*/
void
miFreeStorage(pSLLBlock)
register ScanLineListBlock *pSLLBlock;
{
register ScanLineListBlock *tmpSLLBlock;
while (pSLLBlock)
{
tmpSLLBlock = pSLLBlock->next;
g_free(pSLLBlock);
pSLLBlock = tmpSLLBlock;
}
}

139
gdk/linux-fb/miscanfill.h Normal file
View File

@ -0,0 +1,139 @@
/* $TOG: miscanfill.h /main/6 1998/02/09 14:48:35 kaleb $ */
/*
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
#ifndef SCANFILLINCLUDED
#define SCANFILLINCLUDED
/*
* scanfill.h
*
* Written by Brian Kelleher; Jan 1985
*
* This file contains a few macros to help track
* the edge of a filled object. The object is assumed
* to be filled in scanline order, and thus the
* algorithm used is an extension of Bresenham's line
* drawing algorithm which assumes that y is always the
* major axis.
* Since these pieces of code are the same for any filled shape,
* it is more convenient to gather the library in one
* place, but since these pieces of code are also in
* the inner loops of output primitives, procedure call
* overhead is out of the question.
* See the author for a derivation if needed.
*/
/*
* In scan converting polygons, we want to choose those pixels
* which are inside the polygon. Thus, we add .5 to the starting
* x coordinate for both left and right edges. Now we choose the
* first pixel which is inside the pgon for the left edge and the
* first pixel which is outside the pgon for the right edge.
* Draw the left pixel, but not the right.
*
* How to add .5 to the starting x coordinate:
* If the edge is moving to the right, then subtract dy from the
* error term from the general form of the algorithm.
* If the edge is moving to the left, then add dy to the error term.
*
* The reason for the difference between edges moving to the left
* and edges moving to the right is simple: If an edge is moving
* to the right, then we want the algorithm to flip immediately.
* If it is moving to the left, then we don't want it to flip until
* we traverse an entire pixel.
*/
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
int dx; /* local storage */ \
\
/* \
* if the edge is horizontal, then it is ignored \
* and assumed not to be processed. Otherwise, do this stuff. \
*/ \
if ((dy) != 0) { \
xStart = (x1); \
dx = (x2) - xStart; \
if (dx < 0) { \
m = dx / (dy); \
m1 = m - 1; \
incr1 = -2 * dx + 2 * (dy) * m1; \
incr2 = -2 * dx + 2 * (dy) * m; \
d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
} else { \
m = dx / (dy); \
m1 = m + 1; \
incr1 = 2 * dx - 2 * (dy) * m1; \
incr2 = 2 * dx - 2 * (dy) * m; \
d = -2 * m * (dy) + 2 * dx; \
} \
} \
}
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
if (m1 > 0) { \
if (d > 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} else {\
if (d >= 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} \
}
/*
* This structure contains all of the information needed
* to run the bresenham algorithm.
* The variables may be hardcoded into the declarations
* instead of using this structure to make use of
* register declarations.
*/
typedef struct {
int minor; /* minor axis */
int d; /* decision variable */
int m, m1; /* slope and slope+1 */
int incr1, incr2; /* error increments */
} BRESINFO;
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
bres.m, bres.m1, bres.incr1, bres.incr2)
#define BRESINCRPGONSTRUCT(bres) \
BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
#endif

507
gdk/linux-fb/mispans.c Normal file
View File

@ -0,0 +1,507 @@
/* $XFree86: xc/programs/Xserver/mi/mispans.c,v 3.1 1998/10/04 09:39:33 dawes Exp $ */
/***********************************************************
Copyright 1989, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mispans.c /main/7 1998/02/09 14:48:44 kaleb $ */
#include "mi.h"
#include "mispans.h"
#include <string.h> /* for memmove */
/*
These routines maintain lists of Spans, in order to implement the
``touch-each-pixel-once'' rules of wide lines and arcs.
Written by Joel McCormack, Summer 1989.
*/
void miInitSpanGroup(spanGroup)
SpanGroup *spanGroup;
{
spanGroup->size = 0;
spanGroup->count = 0;
spanGroup->group = NULL;
spanGroup->ymin = SHRT_MAX;
spanGroup->ymax = SHRT_MIN;
} /* InitSpanGroup */
#define YMIN(spans) (spans->points[0].y)
#define YMAX(spans) (spans->points[spans->count-1].y)
void miSubtractSpans (spanGroup, sub)
SpanGroup *spanGroup;
Spans *sub;
{
int i, subCount, spansCount;
int ymin, ymax, xmin, xmax;
Spans *spans;
GdkRectangle* subPt, *spansPt;
int extra;
ymin = YMIN(sub);
ymax = YMAX(sub);
spans = spanGroup->group;
for (i = spanGroup->count; i; i--, spans++) {
if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) {
subCount = sub->count;
subPt = sub->points;
spansCount = spans->count;
spansPt = spans->points;
extra = 0;
for (;;)
{
while (spansCount && spansPt->y < subPt->y)
{
spansPt++; spansCount--;
}
if (!spansCount)
break;
while (subCount && subPt->y < spansPt->y)
{
subPt++; subCount--;
}
if (!subCount)
break;
if (subPt->y == spansPt->y)
{
xmin = subPt->x;
xmax = xmin + subPt->width;
if (xmin >= (spansPt->x + spansPt->width) || spansPt->x >= xmax)
{
;
}
else if (xmin <= spansPt->x)
{
if (xmax >= (spansPt->x + spansPt->width))
{
g_memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1));
spansPt--;
spans->count--;
extra++;
}
else
{
spansPt->width -= xmax - spansPt->x;
spansPt->x = xmax;
}
}
else
{
if (xmax >= (spansPt->x + spansPt->width))
{
spansPt->width = xmin - spansPt->x;
}
else
{
if (!extra) {
GdkRectangle* newPt;
#define EXTRA 8
newPt = (GdkRectangle*) g_realloc (spans->points, (spans->count + EXTRA) * sizeof (GdkRectangle));
if (!newPt)
break;
spansPt = newPt + (spansPt - spans->points);
spans->points = newPt;
extra = EXTRA;
}
g_memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount));
spans->count++;
extra--;
spansPt->width = xmin - spansPt->x;
spansPt->height = 1;
spansPt++;
spansPt->width -= xmax - spansPt->x;
spansPt->height = 1;
spansPt->x = xmax;
}
}
}
spansPt++; spansCount--;
}
}
}
}
void miAppendSpans(spanGroup, otherGroup, spans)
SpanGroup *spanGroup;
SpanGroup *otherGroup;
Spans *spans;
{
register int ymin, ymax;
register int spansCount;
spansCount = spans->count;
if (spansCount > 0) {
if (spanGroup->size == spanGroup->count) {
spanGroup->size = (spanGroup->size + 8) * 2;
spanGroup->group = (Spans *)
g_realloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
}
spanGroup->group[spanGroup->count] = *spans;
(spanGroup->count)++;
ymin = spans->points[0].y;
if (ymin < spanGroup->ymin) spanGroup->ymin = ymin;
ymax = spans->points[spansCount - 1].y;
if (ymax > spanGroup->ymax) spanGroup->ymax = ymax;
if (otherGroup &&
otherGroup->ymin < ymax &&
ymin < otherGroup->ymax)
{
miSubtractSpans (otherGroup, spans);
}
}
else
{
g_free (spans->points);
}
} /* AppendSpans */
void miFreeSpanGroup(spanGroup)
SpanGroup *spanGroup;
{
if (spanGroup->group != NULL) g_free(spanGroup->group);
}
static void QuickSortSpansX(points, numSpans)
register GdkRectangle points[];
register int numSpans;
{
register int x;
register int i, j, m;
register GdkRectangle* r;
/* Always called with numSpans > 1 */
/* Sorts only by x, as all y should be the same */
#define ExchangeSpans(a, b) \
{ \
GdkRectangle tpt; \
\
tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
}
do {
if (numSpans < 9) {
/* Do insertion sort */
register int xprev;
xprev = points[0].x;
i = 1;
do { /* while i != numSpans */
x = points[i].x;
if (xprev > x) {
/* points[i] is out of order. Move into proper location. */
GdkRectangle tpt;
int k;
for (j = 0; x >= points[j].x; j++) {}
tpt = points[i];
for (k = i; k != j; k--) {
points[k] = points[k-1];
}
points[j] = tpt;
x = points[i].x;
} /* if out of order */
xprev = x;
i++;
} while (i != numSpans);
return;
}
/* Choose partition element, stick in location 0 */
m = numSpans / 2;
if (points[m].x > points[0].x) ExchangeSpans(m, 0);
if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1);
if (points[m].x > points[0].x) ExchangeSpans(m, 0);
x = points[0].x;
/* Partition array */
i = 0;
j = numSpans;
do {
r = &(points[i]);
do {
r++;
i++;
} while (i != numSpans && r->x < x);
r = &(points[j]);
do {
r--;
j--;
} while (x < r->x);
if (i < j) ExchangeSpans(i, j);
} while (i < j);
/* Move partition element back to middle */
ExchangeSpans(0, j);
/* Recurse */
if (numSpans-j-1 > 1)
QuickSortSpansX(&points[j+1], numSpans-j-1);
numSpans = j;
} while (numSpans > 1);
} /* QuickSortSpans */
static int UniquifySpansX(spans, newPoints, newWidths)
Spans *spans;
register GdkRectangle *newPoints;
{
register int newx1, newx2, oldpt, i, y;
GdkRectangle *oldPoints, *startNewPoints = newPoints;
/* Always called with numSpans > 1 */
/* Uniquify the spans, and stash them into newPoints and newWidths. Return the
number of unique spans. */
oldPoints = spans->points;
y = oldPoints->y;
newx1 = oldPoints->x;
newx2 = newx1 + oldPoints->width;
for (i = spans->count-1; i != 0; i--) {
oldPoints++;
oldpt = oldPoints->x;
if (oldpt > newx2) {
/* Write current span, start a new one */
newPoints->x = newx1;
newPoints->y = y;
newPoints->width = newx2 - newx1;
newPoints->height = 1;
newPoints++;
newx1 = oldpt;
newx2 = oldpt + oldPoints->width;
} else {
/* extend current span, if old extends beyond new */
oldpt = oldpt + oldPoints->width;
if (oldpt > newx2) newx2 = oldpt;
}
} /* for */
/* Write final span */
newPoints->x = newx1;
newPoints->width = newx2 - newx1;
newPoints->height = 1;
newPoints->y = y;
return (newPoints - startNewPoints) + 1;
} /* UniquifySpansX */
void
miDisposeSpanGroup (spanGroup)
SpanGroup *spanGroup;
{
int i;
Spans *spans;
for (i = 0; i < spanGroup->count; i++)
{
spans = spanGroup->group + i;
g_free (spans->points);
}
}
void miFillUniqueSpanGroup(pDraw, pGC, spanGroup)
GdkDrawable* pDraw;
GdkGC* pGC;
SpanGroup *spanGroup;
{
register int i;
register Spans *spans;
register Spans *yspans;
register int *ysizes;
register int ymin, ylength;
/* Outgoing spans for one big call to FillSpans */
register GdkRectangle* points;
register int count;
if (spanGroup->count == 0) return;
if (spanGroup->count == 1) {
/* Already should be sorted, unique */
spans = spanGroup->group;
gdk_fb_fill_spans(pDraw, pGC, spans->points, spans->count);
g_free(spans->points);
}
else
{
/* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
/* This seems to be the fastest thing to do. I've tried sorting on
both x and y at the same time rather than creating into all those
y buckets, but it was somewhat slower. */
ymin = spanGroup->ymin;
ylength = spanGroup->ymax - ymin + 1;
/* Allocate Spans for y buckets */
yspans = (Spans *) g_malloc(ylength * sizeof(Spans));
ysizes = (int *) g_malloc(ylength * sizeof (int));
if (!yspans || !ysizes)
{
if (yspans)
g_free (yspans);
if (ysizes)
g_free (ysizes);
miDisposeSpanGroup (spanGroup);
return;
}
for (i = 0; i != ylength; i++) {
ysizes[i] = 0;
yspans[i].count = 0;
yspans[i].points = NULL;
}
/* Go through every single span and put it into the correct bucket */
count = 0;
for (i = 0, spans = spanGroup->group;
i != spanGroup->count;
i++, spans++) {
int index;
int j;
for (j = 0, points = spans->points;
j != spans->count;
j++, points++) {
index = points->y - ymin;
if (index >= 0 && index < ylength) {
Spans *newspans = &(yspans[index]);
if (newspans->count == ysizes[index]) {
GdkRectangle* newpoints;
ysizes[index] = (ysizes[index] + 8) * 2;
newpoints = (GdkRectangle*) g_realloc(
newspans->points,
ysizes[index] * sizeof(GdkRectangle));
if (!newpoints)
{
int i;
for (i = 0; i < ylength; i++)
{
g_free (yspans[i].points);
}
g_free (yspans);
g_free (ysizes);
miDisposeSpanGroup (spanGroup);
return;
}
newspans->points = newpoints;
}
newspans->points[newspans->count] = *points;
(newspans->count)++;
} /* if y value of span in range */
} /* for j through spans */
count += spans->count;
g_free(spans->points);
spans->points = NULL;
} /* for i thorough Spans */
/* Now sort by x and uniquify each bucket into the final array */
points = (GdkRectangle*) g_malloc(count * sizeof(GdkRectangle));
if (!points)
{
int i;
for (i = 0; i < ylength; i++)
{
g_free (yspans[i].points);
}
g_free (yspans);
g_free (ysizes);
if (points)
g_free (points);
return;
}
count = 0;
for (i = 0; i != ylength; i++) {
int ycount = yspans[i].count;
if (ycount > 0) {
if (ycount > 1) {
QuickSortSpansX(yspans[i].points, ycount);
count += UniquifySpansX
(&(yspans[i]), &(points[count]));
} else {
points[count] = yspans[i].points[0];
count++;
}
g_free(yspans[i].points);
}
}
gdk_fb_fill_spans(pDraw, pGC, points, count);
g_free(points);
g_free(yspans);
g_free(ysizes); /* use (DE)ALLOCATE_LOCAL for these? */
}
spanGroup->count = 0;
spanGroup->ymin = SHRT_MAX;
spanGroup->ymax = SHRT_MIN;
}
void miFillSpanGroup(pDraw, pGC, spanGroup)
GdkDrawable* pDraw;
GdkGC* pGC;
SpanGroup *spanGroup;
{
register int i;
register Spans *spans;
for (i = 0, spans = spanGroup->group; i != spanGroup->count; i++, spans++) {
gdk_fb_fill_spans(pDraw, pGC, spans->points, spans->count);
g_free(spans->points);
}
spanGroup->count = 0;
spanGroup->ymin = SHRT_MAX;
spanGroup->ymax = SHRT_MIN;
} /* FillSpanGroup */

127
gdk/linux-fb/mispans.h Normal file
View File

@ -0,0 +1,127 @@
/***********************************************************
Copyright 1989, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mispans.h /main/5 1998/02/09 14:48:48 kaleb $ */
typedef struct {
int count; /* number of spans */
GdkRectangle* points; /* pointer to list of start points */
} Spans;
typedef struct {
int size; /* Total number of *Spans allocated */
int count; /* Number of *Spans actually in group */
Spans *group; /* List of Spans */
int ymin, ymax; /* Min, max y values encountered */
} SpanGroup;
/* Initialize SpanGroup. MUST BE DONE before use. */
extern void miInitSpanGroup(
#if NeedFunctionPrototypes
SpanGroup * /*spanGroup*/
#endif
);
/* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */
extern void miAppendSpans(
#if NeedFunctionPrototypes
SpanGroup * /*spanGroup*/,
SpanGroup * /*otherGroup*/,
Spans * /*spans*/
#endif
);
/* Paint a span group, possibly with some overlap */
extern void miFillSpanGroup(
#if NeedFunctionPrototypes
GdkDrawable* /*pDraw*/,
GdkGC* /*pGC*/,
SpanGroup * /*spanGroup*/
#endif
);
/* Paint a span group, insuring that each pixel is painted at most once */
extern void miFillUniqueSpanGroup(
#if NeedFunctionPrototypes
GdkDrawable* /*pDraw*/,
GdkGC* /*pGC*/,
SpanGroup * /*spanGroup*/
#endif
);
/* Free up data in a span group. MUST BE DONE or you'll suffer memory leaks */
extern void miFreeSpanGroup(
#if NeedFunctionPrototypes
SpanGroup * /*spanGroup*/
#endif
);
extern void miSubtractSpans(
#if NeedFunctionPrototypes
SpanGroup * /*spanGroup*/,
Spans * /*sub*/
#endif
);
extern void miDisposeSpanGroup(
#if NeedFunctionPrototypes
SpanGroup * /*spanGroup*/
#endif
);
extern int miClipSpans(
#if NeedFunctionPrototypes
GdkRegion* /*prgnDst*/,
GdkPoint* /*ppt*/,
int * /*pwidth*/,
int /*nspans*/,
GdkPoint* /*pptNew*/,
int * /*pwidthNew*/,
int /*fSorted*/
#endif
);
/* Rops which must use span groups */
#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
#define miSpansEasyRop(rop) (!miSpansCarefulRop(rop))

58
gdk/linux-fb/mistruct.h Normal file
View File

@ -0,0 +1,58 @@
/* $TOG: mistruct.h /main/4 1998/02/09 14:49:07 kaleb $ */
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#ifndef MISTRUCT_H
#define MISTRUCT_H
#include "mitypes.h"
/* information about dashes */
typedef struct _miDash {
GdkPoint pt;
int e1, e2; /* keep these, so we don't have to do it again */
int e; /* bresenham error term for this point on line */
int which;
int newLine;/* 0 if part of same original line as previous dash */
} miDashRec;
#endif /* MISTRUCT_H */

486
gdk/linux-fb/mitypes.h Normal file
View File

@ -0,0 +1,486 @@
#ifndef MITYPES_H
#define MITYPES_H
#include <alloca.h>
#define ALLOCATE_LOCAL(size) alloca((int)(size))
#define DEALLOCATE_LOCAL(ptr) /* as nothing */
#include <stdlib.h>
#include <glib.h>
#include <gdk/gdk.h>
#include <gdkfb.h>
#include <gdkprivate-fb.h>
#include <gdkregion-generic.h>
typedef struct _miDash *miDashPtr;
#define CT_NONE 0
#define CT_PIXMAP 1
#define CT_REGION 2
#define CT_UNSORTED 6
#define CT_YSORTED 10
#define CT_YXSORTED 14
#define CT_YXBANDED 18
struct _GdkGCFuncs {
void (* ValidateGC)(
GdkGC* /*pGC*/,
unsigned long /*stateChanges*/,
GdkDrawable* /*pDrawable*/
);
void (* ChangeGC)(
GdkGC* /*pGC*/,
unsigned long /*mask*/
);
void (* CopyGC)(
GdkGC* /*pGCSrc*/,
unsigned long /*mask*/,
GdkGC* /*pGCDst*/
);
void (* DestroyGC)(
GdkGC* /*pGC*/
);
void (* ChangeClip)(
GdkGC* /*pGC*/,
int /*type*/,
gpointer /*pvalue*/,
int /*nrects*/
);
void (* DestroyClip)(
GdkGC* /*pGC*/
);
void (* CopyClip)(
GdkGC* /*pgcDst*/,
GdkGC* /*pgcSrc*/
);
};
typedef union {
guint32 val;
gpointer ptr;
} ChangeGCVal, *ChangeGCValPtr;
#define PixmapBytePad(w, d) (w)
#define BitmapBytePad(w) (w)
#if 0
typedef struct _PaddingInfo {
int padRoundUp; /* pixels per pad unit - 1 */
int padPixelsLog2; /* log 2 (pixels per pad unit) */
int padBytesLog2; /* log 2 (bytes per pad unit) */
int notPower2; /* bitsPerPixel not a power of 2 */
int bytesPerPixel; /* only set when notPower2 is TRUE */
} PaddingInfo;
extern PaddingInfo PixmapWidthPaddingInfo[];
#define PixmapWidthInPadUnits(w, d) \
(PixmapWidthPaddingInfo[d].notPower2 ? \
(((int)(w) * PixmapWidthPaddingInfo[d].bytesPerPixel + \
PixmapWidthPaddingInfo[d].bytesPerPixel) >> \
PixmapWidthPaddingInfo[d].padBytesLog2) : \
((int)((w) + PixmapWidthPaddingInfo[d].padRoundUp) >> \
PixmapWidthPaddingInfo[d].padPixelsLog2))
#define PixmapBytePad(w, d) \
(PixmapWidthInPadUnits(w, d) << PixmapWidthPaddingInfo[d].padBytesLog2)
#define BitmapBytePad(w) \
(((int)((w) + BITMAP_SCANLINE_PAD - 1) >> LOG2_BITMAP_PAD) << LOG2_BYTES_PER_SCANLINE_PAD)
typedef struct _GdkDrawable GdkPixmap, *GdkPixmap*;
typedef struct _GdkDrawable GdkDrawable, *GdkDrawable*;
typedef struct _GdkGCOps GdkGCOps;
typedef struct _Region Region, *GdkRegion*;
#define EVEN_DASH 0
#define ODD_DASH ~0
typedef struct _GdkPoint {
gint16 x, y;
} GdkPoint, *GdkPoint*;
typedef struct _GdkGC {
unsigned char depth;
unsigned char alu;
unsigned short line_width;
unsigned short dashOffset;
unsigned short numInDashList;
unsigned char *dash;
unsigned int lineStyle : 2;
unsigned int capStyle : 2;
unsigned int joinStyle : 2;
unsigned int fillStyle : 2;
unsigned int fillRule : 1;
unsigned int arcMode : 1;
unsigned int subWindowMode : 1;
unsigned int graphicsExposures : 1;
unsigned int clientClipType : 2; /* CT_<kind> */
unsigned int miTranslate:1; /* should mi things translate? */
unsigned int tileIsPixel:1; /* tile is solid pixel */
unsigned int fExpose:1; /* Call exposure handling */
unsigned int freeCompClip:1; /* Free composite clip */
unsigned int unused:14; /* see comment above */
unsigned long planemask;
unsigned long fgPixel;
unsigned long bgPixel;
/*
* alas -- both tile and stipple must be here as they
* are independently specifiable
*/
/* PixUnion tile;
GdkPixmap* stipple;*/
GdkPoint patOrg; /* origin for (tile, stipple) */
struct _Font *font;
GdkPoint clipOrg;
GdkPoint lastWinOrg; /* position of window last validated */
gpointer clientClip;
unsigned long stateChanges; /* masked with GC_<kind> */
unsigned long serialNumber;
/* GCFuncs *funcs; */
GdkGCOps *ops;
} GdkGC, *GdkGC*;
struct _GdkDrawable {
unsigned char type; /* DRAWABLE_<type> */
unsigned char depth;
unsigned char bitsPerPixel;
short x; /* window: screen absolute, pixmap: 0 */
short y; /* window: screen absolute, pixmap: 0 */
unsigned short width;
unsigned short height;
unsigned long serialNumber;
guchar *buffer;
int rowStride;
};
typedef struct _GdkSegment {
gint16 x1, y1, x2, y2;
} GdkSegment;
typedef struct _GdkRectangle {
gint16 x, y;
guint16 width, height;
} GdkRectangle, *GdkRectangle*;
typedef struct _Box {
short x1, y1, x2, y2;
} BoxRec, *BoxPtr;
/*
* graphics operations invoked through a GC
*/
/* graphics functions, as in GC.alu */
#define GDK_CLEAR 0x0 /* 0 */
#define GDK_AND 0x1 /* src AND dst */
#define GDK_AND_REVERSE 0x2 /* src AND NOT dst */
#define GDK_COPY 0x3 /* src */
#define GDK_AND_INVERT 0x4 /* NOT src AND dst */
#define GDK_NOOP 0x5 /* dst */
#define GDK_XOR 0x6 /* src XOR dst */
#define GDK_OR 0x7 /* src OR dst */
#define GDK_NOR 0x8 /* NOT src AND NOT dst */
#define GDK_EQUIV 0x9 /* NOT src XOR dst */
#define GDK_INVERT 0xa /* NOT dst */
#define GDK_OR_REVERSE 0xb /* src OR NOT dst */
#define GDK_COPY_INVERT 0xc /* NOT src */
#define GDK_OR_INVERT 0xd /* NOT src OR dst */
#define GDK_NAND 0xe /* NOT src OR NOT dst */
#define GDK_SET 0xf /* 1 */
/* CoordinateMode for drawing routines */
#define CoordModeOrigin 0 /* relative to the origin */
#define CoordModePrevious 1 /* relative to previous point */
/* Polygon shapes */
#define Complex 0 /* paths may intersect */
#define Nonconvex 1 /* no paths intersect, but not convex */
#define Convex 2 /* wholly convex */
/* LineStyle */
#define GDK_LINE_SOLID 0
#define GDK_LINE_ON_OFF_DASH 1
#define GDK_LINE_DOUBLE_DASH 2
/* capStyle */
#define GDK_CAP_NOT_LAST 0
#define GDK_CAP_BUTT 1
#define GDK_CAP_ROUND 2
#define GDK_CAP_PROJECTING 3
/* joinStyle */
#define GDK_JOIN_MITER 0
#define GDK_JOIN_ROUND 1
#define GDK_JOIN_BEVEL 2
/* Arc modes for PolyFillArc */
#define ArcChord 0 /* join endpoints of arc */
#define ArcPieSlice 1 /* join endpoints to center of arc */
/* fillRule */
#define EvenOddRule 0
#define WindingRule 1
/* fillStyle */
#define GDK_SOLID 0
#define GDK_TILED 1
#define GDK_STIPPLED 2
#define GDK_OPAQUE_STIPPLED 3
typedef enum { Linear8Bit, TwoD8Bit, Linear16Bit, TwoD16Bit } FontEncoding;
#define MININT G_MININT
#define MAXINT G_MAXINT
#define MINSHORT G_MINSHORT
#define MAXSHORT G_MAXSHORT
/* GC components: masks used in CreateGC, CopyGC, ChangeGC, OR'ed into
GC.stateChanges */
#define GDK_GC_FUNCTION (1L<<0)
#define GCPlaneMask (1L<<1)
#define GDK_GC_FOREGROUND (1L<<2)
#define GDK_GC_BACKGROUND (1L<<3)
#define GDK_GC_LINE_WIDTH (1L<<4)
#define GCLineStyle (1L<<5)
#define GDK_GC_CAP_STYLE (1L<<6)
#define GDK_GC_JOIN_STYLE (1L<<7)
#define GDK_GC_FILL_STYLE (1L<<8)
#define GCFillRule (1L<<9)
#define GCTile (1L<<10)
#define GDK_GC_STIPPLE (1L<<11)
#define GDK_GC_TS_X_ORIGIN (1L<<12)
#define GDK_GC_TS_Y_ORIGIN (1L<<13)
#define GCFont (1L<<14)
#define GCSubwindowMode (1L<<15)
#define GCGraphicsExposures (1L<<16)
#define GCClipXOrigin (1L<<17)
#define GCClipYOrigin (1L<<18)
#define GCClipMask (1L<<19)
#define GCDashOffset (1L<<20)
#define GCDashList (1L<<21)
#define GCArcMode (1L<<22)
/* types for Drawable */
#define GDK_WINDOW_CHILD 0
#define GDK_DRAWABLE_PIXMAP 1
#define GDK_WINDOW_FOREIGN 2
#define GDK_WINDOW_TEMP 3
#endif
typedef GdkSegment BoxRec, *BoxPtr;
typedef struct _miArc {
gint16 x, y;
guint16 width, height;
gint16 angle1, angle2;
} miArc;
struct _GdkGCOps {
void (* FillSpans)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*nInit*/,
GdkPoint* /*pptInit*/,
int * /*pwidthInit*/,
int /*fSorted*/
);
void (* SetSpans)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
char * /*psrc*/,
GdkPoint* /*ppt*/,
int * /*pwidth*/,
int /*nspans*/,
int /*fSorted*/
);
void (* PutImage)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*depth*/,
int /*x*/,
int /*y*/,
int /*w*/,
int /*h*/,
int /*leftPad*/,
int /*format*/,
char * /*pBits*/
);
GdkRegion* (* CopyArea)(
GdkDrawable* /*pSrc*/,
GdkDrawable* /*pDst*/,
GdkGC* /*pGC*/,
int /*srcx*/,
int /*srcy*/,
int /*w*/,
int /*h*/,
int /*dstx*/,
int /*dsty*/
);
GdkRegion* (* CopyPlane)(
GdkDrawable* /*pSrcDrawable*/,
GdkDrawable* /*pDstDrawable*/,
GdkGC* /*pGC*/,
int /*srcx*/,
int /*srcy*/,
int /*width*/,
int /*height*/,
int /*dstx*/,
int /*dsty*/,
unsigned long /*bitPlane*/
);
void (* PolyPoint)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*mode*/,
int /*npt*/,
GdkPoint* /*pptInit*/
);
void (* Polylines)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*mode*/,
int /*npt*/,
GdkPoint* /*pptInit*/
);
void (* PolySegment)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*nseg*/,
GdkSegment * /*pSegs*/
);
void (* PolyRectangle)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*nrects*/,
GdkRectangle * /*pRects*/
);
void (* PolyArc)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*narcs*/,
miArc * /*parcs*/
);
void (* FillPolygon)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*shape*/,
int /*mode*/,
int /*count*/,
GdkPoint* /*pPts*/
);
void (* PolyFillRect)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*nrectFill*/,
GdkRectangle * /*prectInit*/
);
void (* PolyFillArc)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*narcs*/,
miArc * /*parcs*/
);
#if 0
int (* PolyText8)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
int /*count*/,
char * /*chars*/
);
int (* PolyText16)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
int /*count*/,
unsigned short * /*chars*/
);
void (* ImageText8)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
int /*count*/,
char * /*chars*/
);
void (* ImageText16)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
int /*count*/,
unsigned short * /*chars*/
);
void (* ImageGlyphBlt)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
unsigned int /*nglyph*/,
CharInfoPtr * /*ppci*/,
pointer /*pglyphBase*/
);
void (* PolyGlyphBlt)(
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
int /*x*/,
int /*y*/,
unsigned int /*nglyph*/,
CharInfoPtr * /*ppci*/,
pointer /*pglyphBase*/
);
#endif
void (* PushPixels)(
GdkGC* /*pGC*/,
GdkPixmap* /*pBitMap*/,
GdkDrawable* /*pDst*/,
int /*w*/,
int /*h*/,
int /*x*/,
int /*y*/
);
};
#define SCRRIGHT(x, n) ((x)>>(n))
#endif /* MITYPES_H */

2108
gdk/linux-fb/miwideline.c Normal file

File diff suppressed because it is too large Load Diff

254
gdk/linux-fb/miwideline.h Normal file
View File

@ -0,0 +1,254 @@
/* $TOG: miwideline.h /main/12 1998/02/09 14:49:26 kaleb $ */
/*
Copyright 1988, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
/* $XFree86: xc/programs/Xserver/mi/miwideline.h,v 1.7 1998/10/04 09:39:35 dawes Exp $ */
/* Author: Keith Packard, MIT X Consortium */
#ifndef MI_WIDELINE_H
#define MI_WIDELINE_H 1
#include "mispans.h"
/*
* interface data to span-merging polygon filler
*/
typedef struct _SpanData {
SpanGroup fgGroup, bgGroup;
} SpanDataRec, *SpanDataPtr;
#define AppendSpanGroup(pGC, pixel, spanPtr, spanData) { \
SpanGroup *group, *othergroup = NULL; \
if (pixel->pixel == GDK_GC_FBDATA(pGC)->values.foreground.pixel) \
{ \
group = &spanData->fgGroup; \
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) \
othergroup = &spanData->bgGroup; \
} \
else \
{ \
group = &spanData->bgGroup; \
othergroup = &spanData->fgGroup; \
} \
miAppendSpans (group, othergroup, spanPtr); \
}
/*
* Polygon edge description for integer wide-line routines
*/
typedef struct _PolyEdge {
int height; /* number of scanlines to process */
int x; /* starting x coordinate */
int stepx; /* fixed integral dx */
int signdx; /* variable dx sign */
int e; /* initial error term */
int dy;
int dx;
} PolyEdgeRec, *PolyEdgePtr;
#define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */
/*
* types for general polygon routines
*/
typedef struct _PolyVertex {
double x, y;
} PolyVertexRec, *PolyVertexPtr;
typedef struct _PolySlope {
int dx, dy;
double k; /* x0 * dy - y0 * dx */
} PolySlopeRec, *PolySlopePtr;
/*
* Line face description for caps/joins
*/
typedef struct _LineFace {
double xa, ya;
int dx, dy;
int x, y;
double k;
} LineFaceRec, *LineFacePtr;
/*
* macros for polygon fillers
*/
#define MIPOLYRELOADLEFT if (!left_height && left_count) { \
left_height = left->height; \
left_x = left->x; \
left_stepx = left->stepx; \
left_signdx = left->signdx; \
left_e = left->e; \
left_dy = left->dy; \
left_dx = left->dx; \
--left_count; \
++left; \
}
#define MIPOLYRELOADRIGHT if (!right_height && right_count) { \
right_height = right->height; \
right_x = right->x; \
right_stepx = right->stepx; \
right_signdx = right->signdx; \
right_e = right->e; \
right_dy = right->dy; \
right_dx = right->dx; \
--right_count; \
++right; \
}
#define MIPOLYSTEPLEFT left_x += left_stepx; \
left_e += left_dx; \
if (left_e > 0) \
{ \
left_x += left_signdx; \
left_e -= left_dy; \
}
#define MIPOLYSTEPRIGHT right_x += right_stepx; \
right_e += right_dx; \
if (right_e > 0) \
{ \
right_x += right_signdx; \
right_e -= right_dy; \
}
#define MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
oldPixel = GDK_GC_FBDATA(pGC)->values.foreground; \
if (pixel->pixel != oldPixel.pixel) { \
gdk_gc_set_foreground(pGC, pixel); \
} \
}
#define MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel) { \
if (pixel->pixel != oldPixel.pixel) { \
gdk_gc_set_foreground(pGC, &oldPixel); \
} \
}
#ifndef ICEIL
#ifdef NOINLINEICEIL
#define ICEIL(x) ((int)ceil(x))
#else
#ifdef __GNUC__
#define ICEIL ICIEL
static __inline int ICEIL(x)
double x;
{
int _cTmp = x;
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp+1;
}
#else
#define ICEIL(x) ((((x) == (_cTmp = (x))) || ((x) < 0.0)) ? _cTmp : _cTmp+1)
#define ICEILTEMPDECL static int _cTmp;
#endif
#endif
#endif
extern void miFillPolyHelper(
#if NeedFunctionPrototypes
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
GdkColor * /*pixel*/,
SpanDataPtr /*spanData*/,
int /*y*/,
int /*overall_height*/,
PolyEdgePtr /*left*/,
PolyEdgePtr /*right*/,
int /*left_count*/,
int /*right_count*/
#endif
);
extern int miRoundJoinFace(
#if NeedFunctionPrototypes
LineFacePtr /*face*/,
PolyEdgePtr /*edge*/,
gboolean * /*leftEdge*/
#endif
);
extern void miRoundJoinClip(
#if NeedFunctionPrototypes
LineFacePtr /*pLeft*/,
LineFacePtr /*pRight*/,
PolyEdgePtr /*edge1*/,
PolyEdgePtr /*edge2*/,
int * /*y1*/,
int * /*y2*/,
gboolean * /*left1*/,
gboolean * /*left2*/
#endif
);
extern int miRoundCapClip(
#if NeedFunctionPrototypes
LineFacePtr /*face*/,
gboolean /*isInt*/,
PolyEdgePtr /*edge*/,
gboolean * /*leftEdge*/
#endif
);
extern void miLineProjectingCap(
#if NeedFunctionPrototypes
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
GdkColor * /*pixel*/,
SpanDataPtr /*spanData*/,
LineFacePtr /*face*/,
gboolean /*isLeft*/,
double /*xorg*/,
double /*yorg*/,
gboolean /*isInt*/
#endif
);
extern SpanDataPtr miSetupSpanData(
#if NeedFunctionPrototypes
GdkGC* /*pGC*/,
SpanDataPtr /*spanData*/,
int /*npt*/
#endif
);
extern void miCleanupSpanData(
#if NeedFunctionPrototypes
GdkDrawable* /*pDrawable*/,
GdkGC* /*pGC*/,
SpanDataPtr /*spanData*/
#endif
);
extern int miPolyBuildEdge(double x0, double y0, double k, int dx, int dy,
int xi, int yi, int left, PolyEdgePtr edge);
extern int miPolyBuildPoly(PolyVertexPtr vertices, PolySlopePtr slopes,
int count, int xi, int yi, PolyEdgePtr left,
PolyEdgePtr right, int *pnleft, int *pnright,
int *h);
#endif

622
gdk/linux-fb/mizerclip.c Normal file
View File

@ -0,0 +1,622 @@
/* $XFree86: xc/programs/Xserver/mi/mizerclip.c,v 1.1 1999/10/13 22:33:13 dawes Exp $ */
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#include "mi.h"
#include "miline.h"
/*
The bresenham error equation used in the mi/mfb/cfb line routines is:
e = error
dx = difference in raw X coordinates
dy = difference in raw Y coordinates
M = # of steps in X direction
N = # of steps in Y direction
B = 0 to prefer diagonal steps in a given octant,
1 to prefer axial steps in a given octant
For X major lines:
e = 2Mdy - 2Ndx - dx - B
-2dx <= e < 0
For Y major lines:
e = 2Ndx - 2Mdy - dy - B
-2dy <= e < 0
At the start of the line, we have taken 0 X steps and 0 Y steps,
so M = 0 and N = 0:
X major e = 2Mdy - 2Ndx - dx - B
= -dx - B
Y major e = 2Ndx - 2Mdy - dy - B
= -dy - B
At the end of the line, we have taken dx X steps and dy Y steps,
so M = dx and N = dy:
X major e = 2Mdy - 2Ndx - dx - B
= 2dxdy - 2dydx - dx - B
= -dx - B
Y major e = 2Ndx - 2Mdy - dy - B
= 2dydx - 2dxdy - dy - B
= -dy - B
Thus, the error term is the same at the start and end of the line.
Let us consider clipping an X coordinate. There are 4 cases which
represent the two independent cases of clipping the start vs. the
end of the line and an X major vs. a Y major line. In any of these
cases, we know the number of X steps (M) and we wish to find the
number of Y steps (N). Thus, we will solve our error term equation.
If we are clipping the start of the line, we will find the smallest
N that satisfies our error term inequality. If we are clipping the
end of the line, we will find the largest number of Y steps that
satisfies the inequality. In that case, since we are representing
the Y steps as (dy - N), we will actually want to solve for the
smallest N in that equation.
Case 1: X major, starting X coordinate moved by M steps
-2dx <= 2Mdy - 2Ndx - dx - B < 0
2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B
2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx
N <= (2Mdy + dx - B) / 2dx
Since we are trying to find the smallest N that satisfies these
equations, we should use the > inequality to find the smallest:
N = floor((2Mdy - dx - B) / 2dx) + 1
= floor((2Mdy - dx - B + 2dx) / 2dx)
= floor((2Mdy + dx - B) / 2dx)
Case 1b: X major, ending X coordinate moved to M steps
Same derivations as Case 1, but we want the largest N that satisfies
the equations, so we use the <= inequality:
N = floor((2Mdy + dx - B) / 2dx)
Case 2: X major, ending X coordinate moved by M steps
-2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
-2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
-2dx <= 2Ndx - 2Mdy - dx - B < 0
2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B
2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx
N >= (2Mdy - dx + B) / 2dx
Since we are trying to find the highest number of Y steps that
satisfies these equations, we need to find the smallest N, so
we should use the >= inequality to find the smallest:
N = ceiling((2Mdy - dx + B) / 2dx)
= floor((2Mdy - dx + B + 2dx - 1) / 2dx)
= floor((2Mdy + dx + B - 1) / 2dx)
Case 2b: X major, starting X coordinate moved to M steps from end
Same derivations as Case 2, but we want the smallest number of Y
steps, so we want the highest N, so we use the < inequality:
N = ceiling((2Mdy + dx + B) / 2dx) - 1
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
= floor((2Mdy + dx + B - 1) / 2dx)
Case 3: Y major, starting X coordinate moved by M steps
-2dy <= 2Ndx - 2Mdy - dy - B < 0
2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B
2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx
N >= (2Mdy - dy + B) / 2dx
Since we are trying to find the smallest N that satisfies these
equations, we should use the >= inequality to find the smallest:
N = ceiling((2Mdy - dy + B) / 2dx)
= floor((2Mdy - dy + B + 2dx - 1) / 2dx)
= floor((2Mdy - dy + B - 1) / 2dx) + 1
Case 3b: Y major, ending X coordinate moved to M steps
Same derivations as Case 3, but we want the largest N that satisfies
the equations, so we use the < inequality:
N = ceiling((2Mdy + dy + B) / 2dx) - 1
= floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
= floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
= floor((2Mdy + dy + B - 1) / 2dx)
Case 4: Y major, ending X coordinate moved by M steps
-2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
-2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
-2dy <= 2Mdy - 2Ndx - dy - B < 0
2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B
2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx
N <= (2Mdy + dy - B) / 2dx
Since we are trying to find the highest number of Y steps that
satisfies these equations, we need to find the smallest N, so
we should use the > inequality to find the smallest:
N = floor((2Mdy - dy - B) / 2dx) + 1
Case 4b: Y major, starting X coordinate moved to M steps from end
Same analysis as Case 4, but we want the smallest number of Y steps
which means the largest N, so we use the <= inequality:
N = floor((2Mdy + dy - B) / 2dx)
Now let's try the Y coordinates, we have the same 4 cases.
Case 5: X major, starting Y coordinate moved by N steps
-2dx <= 2Mdy - 2Ndx - dx - B < 0
2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B
2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy
M >= (2Ndx - dx + B) / 2dy
Since we are trying to find the smallest M, we use the >= inequality:
M = ceiling((2Ndx - dx + B) / 2dy)
= floor((2Ndx - dx + B + 2dy - 1) / 2dy)
= floor((2Ndx - dx + B - 1) / 2dy) + 1
Case 5b: X major, ending Y coordinate moved to N steps
Same derivations as Case 5, but we want the largest M that satisfies
the equations, so we use the < inequality:
M = ceiling((2Ndx + dx + B) / 2dy) - 1
= floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
= floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
= floor((2Ndx + dx + B - 1) / 2dy)
Case 6: X major, ending Y coordinate moved by N steps
-2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
-2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
-2dx <= 2Ndx - 2Mdy - dx - B < 0
2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B
2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy
M <= (2Ndx + dx - B) / 2dy
Largest # of X steps means smallest M, so use the > inequality:
M = floor((2Ndx - dx - B) / 2dy) + 1
Case 6b: X major, starting Y coordinate moved to N steps from end
Same derivations as Case 6, but we want the smallest # of X steps
which means the largest M, so use the <= inequality:
M = floor((2Ndx + dx - B) / 2dy)
Case 7: Y major, starting Y coordinate moved by N steps
-2dy <= 2Ndx - 2Mdy - dy - B < 0
2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B
2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy
M <= (2Ndx + dy - B) / 2dy
To find the smallest M, use the > inequality:
M = floor((2Ndx - dy - B) / 2dy) + 1
= floor((2Ndx - dy - B + 2dy) / 2dy)
= floor((2Ndx + dy - B) / 2dy)
Case 7b: Y major, ending Y coordinate moved to N steps
Same derivations as Case 7, but we want the largest M that satisfies
the equations, so use the <= inequality:
M = floor((2Ndx + dy - B) / 2dy)
Case 8: Y major, ending Y coordinate moved by N steps
-2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
-2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
-2dy <= 2Mdy - 2Ndx - dy - B < 0
2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B
2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy
M >= (2Ndx - dy + B) / 2dy
To find the highest X steps, find the smallest M, use the >= inequality:
M = ceiling((2Ndx - dy + B) / 2dy)
= floor((2Ndx - dy + B + 2dy - 1) / 2dy)
= floor((2Ndx + dy + B - 1) / 2dy)
Case 8b: Y major, starting Y coordinate moved to N steps from the end
Same derivations as Case 8, but we want to find the smallest # of X
steps which means the largest M, so we use the < inequality:
M = ceiling((2Ndx + dy + B) / 2dy) - 1
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
= floor((2Ndx + dy + B - 1) / 2dy)
So, our equations are:
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx)
2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1
3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx)
4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1
4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx)
5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1
5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy)
6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1
6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy)
7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy)
7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy)
8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
We have the following constraints on all of the above terms:
0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine
0 <= dx/dy <= 2^16 - 1
0 <= B <= 1
The floor in all of the above equations can be accomplished with a
simple C divide operation provided that both numerator and denominator
are positive.
Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
and moving a Y coordinate implies dy != 0, we know that the denominators
are all > 0.
For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
or > 0 to prove that the numerators are positive (or zero).
For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
constraints, the first four equations all have numerators >= 0.
For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy
or (2Mdy + dy) > 0. So all of their numerators are >= 0.
For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0.
For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
are > 0.
To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This
is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
<= 2^16 * (2^16 - 1) + (2^16 - 1)
<= 2^32 - 2^16 + 2^16 - 1
<= 2^32 - 1
Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
the numerator is therefore (2^32 - 1), which does not overflow an unsigned
32 bit variable.
*/
/* Bit codes for the terms of the 16 clipping equations defined below. */
#define T_2NDX (1 << 0)
#define T_2MDY (0) /* implicit term */
#define T_DXNOTY (1 << 1)
#define T_DYNOTX (0) /* implicit term */
#define T_SUBDXORY (1 << 2)
#define T_ADDDX (T_DXNOTY) /* composite term */
#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */
#define T_ADDDY (T_DYNOTX) /* composite term */
#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */
#define T_BIASSUBONE (1 << 3)
#define T_SUBBIAS (0) /* implicit term */
#define T_DIV2DX (1 << 4)
#define T_DIV2DY (0) /* implicit term */
#define T_ADDONE (1 << 5)
/* Bit masks defining the 16 equations used in miZeroClipLine. */
#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE)
#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX)
#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE)
#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY)
#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
/* miZeroClipLine
*
* returns: 1 for partially clipped line
* -1 for completely clipped line
*
*/
int
miZeroClipLine(xmin, ymin, xmax, ymax,
new_x1, new_y1, new_x2, new_y2,
adx, ady,
pt1_clipped, pt2_clipped, octant, bias, oc1, oc2)
int xmin, ymin, xmax, ymax;
int *new_x1, *new_y1, *new_x2, *new_y2;
int *pt1_clipped, *pt2_clipped;
unsigned int adx, ady;
int octant;
unsigned int bias;
int oc1, oc2;
{
int swapped = 0;
int clipDone = 0;
guint32 utmp;
int clip1, clip2;
int x1, y1, x2, y2;
int x1_orig, y1_orig, x2_orig, y2_orig;
int xmajor;
int negslope, anchorval;
unsigned int eqn;
x1 = x1_orig = *new_x1;
y1 = y1_orig = *new_y1;
x2 = x2_orig = *new_x2;
y2 = y2_orig = *new_y2;
clip1 = 0;
clip2 = 0;
xmajor = IsXMajorOctant(octant);
bias = ((bias >> octant) & 1);
while (1)
{
if ((oc1 & oc2) != 0) /* trivial reject */
{
clipDone = -1;
clip1 = oc1;
clip2 = oc2;
break;
}
else if ((oc1 | oc2) == 0) /* trivial accept */
{
clipDone = 1;
if (swapped)
{
SWAPINT_PAIR(x1, y1, x2, y2);
SWAPINT(clip1, clip2);
}
break;
}
else /* have to clip */
{
/* only clip one point at a time */
if (oc1 == 0)
{
SWAPINT_PAIR(x1, y1, x2, y2);
SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig);
SWAPINT(oc1, oc2);
SWAPINT(clip1, clip2);
swapped = !swapped;
}
clip1 |= oc1;
if (oc1 & OUT_LEFT)
{
negslope = IsYDecreasingOctant(octant);
utmp = xmin - x1_orig;
if (utmp <= 32767) /* clip based on near endpt */
{
if (xmajor)
eqn = (swapped) ? EQN2 : EQN1;
else
eqn = (swapped) ? EQN4 : EQN3;
anchorval = y1_orig;
}
else /* clip based on far endpt */
{
utmp = x2_orig - xmin;
if (xmajor)
eqn = (swapped) ? EQN1B : EQN2B;
else
eqn = (swapped) ? EQN3B : EQN4B;
anchorval = y2_orig;
negslope = !negslope;
}
x1 = xmin;
}
else if (oc1 & OUT_ABOVE)
{
negslope = IsXDecreasingOctant(octant);
utmp = ymin - y1_orig;
if (utmp <= 32767) /* clip based on near endpt */
{
if (xmajor)
eqn = (swapped) ? EQN6 : EQN5;
else
eqn = (swapped) ? EQN8 : EQN7;
anchorval = x1_orig;
}
else /* clip based on far endpt */
{
utmp = y2_orig - ymin;
if (xmajor)
eqn = (swapped) ? EQN5B : EQN6B;
else
eqn = (swapped) ? EQN7B : EQN8B;
anchorval = x2_orig;
negslope = !negslope;
}
y1 = ymin;
}
else if (oc1 & OUT_RIGHT)
{
negslope = IsYDecreasingOctant(octant);
utmp = x1_orig - xmax;
if (utmp <= 32767) /* clip based on near endpt */
{
if (xmajor)
eqn = (swapped) ? EQN2 : EQN1;
else
eqn = (swapped) ? EQN4 : EQN3;
anchorval = y1_orig;
}
else /* clip based on far endpt */
{
/*
* Technically since the equations can handle
* utmp == 32768, this overflow code isn't
* needed since X11 protocol can't generate
* a line which goes more than 32768 pixels
* to the right of a clip rectangle.
*/
utmp = xmax - x2_orig;
if (xmajor)
eqn = (swapped) ? EQN1B : EQN2B;
else
eqn = (swapped) ? EQN3B : EQN4B;
anchorval = y2_orig;
negslope = !negslope;
}
x1 = xmax;
}
else if (oc1 & OUT_BELOW)
{
negslope = IsXDecreasingOctant(octant);
utmp = y1_orig - ymax;
if (utmp <= 32767) /* clip based on near endpt */
{
if (xmajor)
eqn = (swapped) ? EQN6 : EQN5;
else
eqn = (swapped) ? EQN8 : EQN7;
anchorval = x1_orig;
}
else /* clip based on far endpt */
{
/*
* Technically since the equations can handle
* utmp == 32768, this overflow code isn't
* needed since X11 protocol can't generate
* a line which goes more than 32768 pixels
* below the bottom of a clip rectangle.
*/
utmp = ymax - y2_orig;
if (xmajor)
eqn = (swapped) ? EQN5B : EQN6B;
else
eqn = (swapped) ? EQN7B : EQN8B;
anchorval = x2_orig;
negslope = !negslope;
}
y1 = ymax;
}
if (swapped)
negslope = !negslope;
utmp <<= 1; /* utmp = 2N or 2M */
if (eqn & T_2NDX)
utmp = (utmp * adx);
else /* (eqn & T_2MDY) */
utmp = (utmp * ady);
if (eqn & T_DXNOTY)
if (eqn & T_SUBDXORY)
utmp -= adx;
else
utmp += adx;
else /* (eqn & T_DYNOTX) */
if (eqn & T_SUBDXORY)
utmp -= ady;
else
utmp += ady;
if (eqn & T_BIASSUBONE)
utmp += bias - 1;
else /* (eqn & T_SUBBIAS) */
utmp -= bias;
if (eqn & T_DIV2DX)
utmp /= (adx << 1);
else /* (eqn & T_DIV2DY) */
utmp /= (ady << 1);
if (eqn & T_ADDONE)
utmp++;
if (negslope)
utmp = -utmp;
if (eqn & T_2NDX) /* We are calculating X steps */
x1 = anchorval + utmp;
else /* else, Y steps */
y1 = anchorval + utmp;
oc1 = 0;
MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax);
}
}
*new_x1 = x1;
*new_y1 = y1;
*new_x2 = x2;
*new_y2 = y2;
*pt1_clipped = clip1;
*pt2_clipped = clip2;
return clipDone;
}

332
gdk/linux-fb/mizerline.c Normal file
View File

@ -0,0 +1,332 @@
/* $XFree86: xc/programs/Xserver/mi/mizerline.c,v 3.4 1999/10/14 04:43:16 dawes Exp $ */
/***********************************************************
Copyright 1987, 1998 The Open Group
All Rights Reserved.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
/* $TOG: mizerline.c /main/18 1998/02/09 14:49:45 kaleb $ */
#include "mi.h"
#include "miline.h"
/* Draw lineSolid, fillStyle-independent zero width lines.
*
* Must keep X and Y coordinates in "ints" at least until after they're
* translated and clipped to accomodate CoordModePrevious lines with very
* large coordinates.
*
* Draws the same pixels regardless of sign(dx) or sign(dy).
*
* Ken Whaley
*
*/
/* largest positive value that can fit into a component of a point.
* Assumes that the point structure is {type x, y;} where type is
* a signed type.
*/
#define MAX_COORDINATE ((1 << (((sizeof(GdkPoint) >> 1) << 3) - 1)) - 1)
#define MI_OUTPUT_POINT(xx, yy)\
{\
if ( !new_span && yy == current_y)\
{\
if (xx < spans->x)\
spans->x = xx;\
spans->width++; \
}\
else\
{\
++Nspans;\
++spans;\
spans->x = xx;\
spans->y = yy;\
spans->width = 1; \
spans->height = 1; \
current_y = yy;\
new_span = FALSE;\
}\
}
void
miZeroLine(pDraw, pGC, mode, npt, pptInit)
GdkDrawable* pDraw;
GdkGC* pGC;
int mode; /* Origin or Previous */
int npt; /* number of points */
GdkPoint* pptInit;
{
int Nspans, current_y;
GdkPoint* ppt;
GdkRectangle* pspanInit, *spans;
int list_len;
int xleft, ytop, xright, ybottom;
int new_x1, new_y1, new_x2, new_y2;
int x, y, x1, y1, x2, y2, xstart, ystart;
int oc1, oc2;
int result;
int pt1_clipped, pt2_clipped = 0;
gboolean new_span;
int signdx, signdy;
int clipdx, clipdy;
int width, height;
int adx, ady;
int octant;
unsigned int bias = miGetZeroLineBias();
int e, e1, e2, e3; /* Bresenham error terms */
int length; /* length of lines == # of pixels on major axis */
xleft = 0;
ytop = 0;
xright = GDK_DRAWABLE_P(pDraw)->width - 1;
ybottom = GDK_DRAWABLE_P(pDraw)->height - 1;
/* it doesn't matter whether we're in drawable or screen coordinates,
* FillSpans simply cannot take starting coordinates outside of the
* range of a GdkPoint component.
*/
/* since we're clipping to the drawable's boundaries & coordinate
* space boundaries, we're guaranteed that the larger of width/height
* is the longest span we'll need to output
*/
width = xright - xleft + 1;
height = ybottom - ytop + 1;
list_len = (height >= width) ? height : width;
pspanInit = (GdkRectangle*)ALLOCATE_LOCAL(list_len * sizeof(GdkRectangle));
if (!pspanInit)
return;
Nspans = 0;
new_span = TRUE;
spans = pspanInit - 1;
ppt = pptInit;
xstart = ppt->x;
ystart = ppt->y;
/* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify
* iteration logic
*/
x2 = xstart;
y2 = ystart;
oc2 = 0;
MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
while (--npt > 0)
{
if (Nspans > 0)
gdk_fb_fill_spans(pDraw, pGC, pspanInit, Nspans);
Nspans = 0;
new_span = TRUE;
spans = pspanInit - 1;
x1 = x2;
y1 = y2;
oc1 = oc2;
++ppt;
x2 = ppt->x;
y2 = ppt->y;
oc2 = 0;
MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
if (adx > ady)
{
e1 = ady << 1;
e2 = e1 - (adx << 1);
e = e1 - adx;
length = adx; /* don't draw endpoint in main loop */
FIXUP_ERROR(e, octant, bias);
new_x1 = x1;
new_y1 = y1;
new_x2 = x2;
new_y2 = y2;
pt1_clipped = 0;
pt2_clipped = 0;
if ((oc1 | oc2) != 0)
{
result = miZeroClipLine(xleft, ytop, xright, ybottom,
&new_x1, &new_y1, &new_x2, &new_y2,
adx, ady,
&pt1_clipped, &pt2_clipped,
octant, bias, oc1, oc2);
if (result == -1)
continue;
length = abs(new_x2 - new_x1);
/* if we've clipped the endpoint, always draw the full length
* of the segment, because then the capstyle doesn't matter
*/
if (pt2_clipped)
length++;
if (pt1_clipped)
{
/* must calculate new error terms */
clipdx = abs(new_x1 - x1);
clipdy = abs(new_y1 - y1);
e += (clipdy * e2) + ((clipdx - clipdy) * e1);
}
}
/* draw the segment */
x = new_x1;
y = new_y1;
e3 = e2 - e1;
e = e - e1;
while (length--)
{
MI_OUTPUT_POINT(x, y);
e += e1;
if (e >= 0)
{
y += signdy;
e += e3;
}
x += signdx;
}
}
else /* Y major line */
{
e1 = adx << 1;
e2 = e1 - (ady << 1);
e = e1 - ady;
length = ady; /* don't draw endpoint in main loop */
SetYMajorOctant(octant);
FIXUP_ERROR(e, octant, bias);
new_x1 = x1;
new_y1 = y1;
new_x2 = x2;
new_y2 = y2;
pt1_clipped = 0;
pt2_clipped = 0;
if ((oc1 | oc2) != 0)
{
result = miZeroClipLine(xleft, ytop, xright, ybottom,
&new_x1, &new_y1, &new_x2, &new_y2,
adx, ady,
&pt1_clipped, &pt2_clipped,
octant, bias, oc1, oc2);
if (result == -1)
continue;
length = abs(new_y2 - new_y1);
/* if we've clipped the endpoint, always draw the full length
* of the segment, because then the capstyle doesn't matter
*/
if (pt2_clipped)
length++;
if (pt1_clipped)
{
/* must calculate new error terms */
clipdx = abs(new_x1 - x1);
clipdy = abs(new_y1 - y1);
e += (clipdx * e2) + ((clipdy - clipdx) * e1);
}
}
/* draw the segment */
x = new_x1;
y = new_y1;
e3 = e2 - e1;
e = e - e1;
while (length--)
{
MI_OUTPUT_POINT(x, y);
e += e1;
if (e >= 0)
{
x += signdx;
e += e3;
}
y += signdy;
}
}
}
/* only do the capnotlast check on the last segment
* and only if the endpoint wasn't clipped. And then, if the last
* point is the same as the first point, do not draw it, unless the
* line is degenerate
*/
if ( (! pt2_clipped) && (GDK_GC_FBDATA(pGC)->values.cap_style != GDK_CAP_NOT_LAST) &&
(((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1)))
{
MI_OUTPUT_POINT(x, y);
}
if (Nspans > 0)
gdk_fb_fill_spans(pDraw, pGC, pspanInit, Nspans);
DEALLOCATE_LOCAL(pspanInit);
}
void
miZeroDashLine(dst, pgc, mode, nptInit, pptInit)
GdkDrawable* dst;
GdkGC* pgc;
int mode;
int nptInit; /* number of points in polyline */
GdkPoint *pptInit; /* points in the polyline */
{
/* XXX kludge until real zero-width dash code is written */
GDK_GC_FBDATA(pgc)->values.line_width = 1;
miWideDash (dst, pgc, mode, nptInit, pptInit);
GDK_GC_FBDATA(pgc)->values.line_width = 0;
}