summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontends/windows/plot.c1176
1 files changed, 668 insertions, 508 deletions
diff --git a/frontends/windows/plot.c b/frontends/windows/plot.c
index fd2961957..5b7648ef1 100644
--- a/frontends/windows/plot.c
+++ b/frontends/windows/plot.c
@@ -50,444 +50,18 @@ HDC plot_hdc;
static RECT plot_clip; /* currently set clipping rectangle */
-static bool clip(const struct rect *clip)
-{
- PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1);
-
- plot_clip.left = clip->x0;
- plot_clip.top = clip->y0;
- plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */
- plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */
-
- return true;
-}
-
-static bool line(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- /* windows 0x00bbggrr */
- DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type ==
- PLOT_OP_TYPE_DOT) ? PS_DOT :
- (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH:
- 0);
- LOGBRUSH lb = {BS_SOLID, col, 0};
- HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (bak == NULL) {
- DeleteObject(pen);
- DeleteObject(clipregion);
- return false;
- }
-/*
- RECT r;
- r.left = x0;
- r.top = y0;
- r.right = x1;
- r.bottom = y1;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- MoveToEx(plot_hdc, x0, y0, (LPPOINT) NULL);
-
- LineTo(plot_hdc, x1, y1);
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, bak);
-
- DeleteObject(pen);
- DeleteObject(clipregion);
-
- return true;
-}
-
-static bool rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
-{
- PLOT_LOG("rectangle from %d,%d to %d,%d", x0, y0, x1, y1);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- x1++;
- y1++;
-
- COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- DWORD penstyle = PS_GEOMETRIC |
- (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT :
- (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH :
- (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL :
- 0)));
- LOGBRUSH lb = {BS_SOLID, pencol, 0};
- LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0};
- if (style->fill_type == PLOT_OP_TYPE_NONE)
- lb1.lbStyle = BS_HOLLOW;
-
- HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
- if (pen == NULL) {
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateBrushIndirect(&lb1);
- if (brush == NULL) {
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
- if (brushbak == NULL) {
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
-
- SelectClipRgn(plot_hdc, clipregion);
-
- Rectangle(plot_hdc, x0, y0, x1, y1);
-
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- SelectClipRgn(plot_hdc, NULL);
- DeleteObject(pen);
- DeleteObject(brush);
- DeleteObject(clipregion);
-
- return true;
-}
-
-
-static bool polygon(const int *p, unsigned int n, const plot_style_t *style)
-{
- PLOT_LOG("polygon %d points", n);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- POINT points[n];
- unsigned int i;
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF);
- COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HPEN penbak = SelectObject(plot_hdc, pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateSolidBrush(brushcol);
- if (brush == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brushbak = SelectObject(plot_hdc, brush);
- if (brushbak == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
- SetPolyFillMode(plot_hdc, WINDING);
- for (i = 0; i < n; i++) {
- points[i].x = (long) p[2 * i];
- points[i].y = (long) p[2 * i + 1];
-
- PLOT_LOG("%ld,%ld ", points[i].x, points[i].y);
- }
-
- SelectClipRgn(plot_hdc, clipregion);
-
- if (n >= 2)
- Polygon(plot_hdc, points, n);
-
- SelectClipRgn(plot_hdc, NULL);
-
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
- DeleteObject(brush);
-
- return true;
-}
-
-
-static bool text(int x, int y, const char *text, size_t length,
- const plot_font_style_t *style)
-{
- PLOT_LOG("words %s at %d,%d", text, x, y);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- HFONT fontbak, font = get_font(style);
- if (font == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- int wlen;
- SIZE s;
- LPWSTR wstring;
- fontbak = (HFONT) SelectObject(plot_hdc, font);
- GetTextExtentPoint(plot_hdc, text, length, &s);
-
-/*
- RECT r;
- r.left = x;
- r.top = y - (3 * s.cy) / 4;
- r.right = x + s.cx;
- r.bottom = y + s.cy / 4;
-*/
- SelectClipRgn(plot_hdc, clipregion);
- SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT);
- if ((style->background & 0xFF000000) != 0x01000000)
- /* 100% alpha */
- SetBkColor(plot_hdc, (DWORD) (style->background & 0x00FFFFFF));
- SetBkMode(plot_hdc, TRANSPARENT);
- SetTextColor(plot_hdc, (DWORD) (style->foreground & 0x00FFFFFF));
-
- wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0);
- wstring = malloc(2 * (wlen + 1));
- if (wstring == NULL) {
- return false;
- }
- MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen);
- TextOutW(plot_hdc, x, y, wstring, wlen);
-
- SelectClipRgn(plot_hdc, NULL);
- free(wstring);
- font = SelectObject(plot_hdc, fontbak);
- DeleteObject(clipregion);
- DeleteObject(font);
-
- return true;
-}
-
-static bool disc(int x, int y, int radius, const plot_style_t *style)
-{
- PLOT_LOG("disc at %d,%d radius %d", x, y, radius);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour)
- & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
- HBRUSH brush = CreateSolidBrush(col);
- if (brush == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- return false;
- }
- HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
- if (brushbak == NULL) {
- DeleteObject(clipregion);
- SelectObject(plot_hdc, penbak);
- DeleteObject(pen);
- DeleteObject(brush);
- return false;
- }
-/*
- RECT r;
- r.left = x - radius;
- r.top = y - radius;
- r.right = x + radius;
- r.bottom = y + radius;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- if (style->fill_type == PLOT_OP_TYPE_NONE)
- Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
- x - radius, y - radius,
- x - radius, y - radius);
- else
- Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius);
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, penbak);
- brush = SelectObject(plot_hdc, brushbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
- DeleteObject(brush);
-
- return true;
-}
-
-static bool arc(int x, int y, int radius, int angle1, int angle2,
- const plot_style_t *style)
-{
- PLOT_LOG("arc centre %d,%d radius %d from %d to %d", x, y, radius,
- angle1, angle2);
-
- /* ensure the plot HDC is set */
- if (plot_hdc == NULL) {
- LOG("HDC not set on call to plotters");
- return false;
- }
-
- HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
- if (clipregion == NULL) {
- return false;
- }
-
- COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
- HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
- if (pen == NULL) {
- DeleteObject(clipregion);
- return false;
- }
- HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
- if (penbak == NULL) {
- DeleteObject(clipregion);
- DeleteObject(pen);
- return false;
- }
-
- int q1, q2;
- double a1=1.0, a2=1.0, b1=1.0, b2=1.0;
- q1 = (int) ((angle1 + 45) / 90) - 45;
- q2 = (int) ((angle2 + 45) / 90) - 45;
- while (q1 > 4)
- q1 -= 4;
- while (q2 > 4)
- q2 -= 4;
- while (q1 <= 0)
- q1 += 4;
- while (q2 <= 0)
- q2 += 4;
- angle1 = ((angle1 + 45) % 90) - 45;
- angle2 = ((angle2 + 45) % 90) - 45;
-
- switch(q1) {
- case 1:
- a1 = 1.0;
- b1 = -tan((M_PI / 180) * angle1);
- break;
- case 2:
- b1 = -1.0;
- a1 = -tan((M_PI / 180) * angle1);
- break;
- case 3:
- a1 = -1.0;
- b1 = tan((M_PI / 180) * angle1);
- break;
- case 4:
- b1 = 1.0;
- a1 = tan((M_PI / 180) * angle1);
- break;
- }
-
- switch(q2) {
- case 1:
- a2 = 1.0;
- b2 = -tan((M_PI / 180) * angle2);
- break;
- case 2:
- b2 = -1.0;
- a2 = -tan((M_PI / 180) * angle2);
- break;
- case 3:
- a2 = -1.0;
- b2 = tan((M_PI / 180) * angle2);
- break;
- case 4:
- b2 = 1.0;
- a2 = tan((M_PI / 180) * angle2);
- break;
- }
-
-/*
- RECT r;
- r.left = x - radius;
- r.top = y - radius;
- r.right = x + radius;
- r.bottom = y + radius;
-*/
- SelectClipRgn(plot_hdc, clipregion);
-
- Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
- x + (int)(a1 * radius), y + (int)(b1 * radius),
- x + (int)(a2 * radius), y + (int)(b2 * radius));
-
- SelectClipRgn(plot_hdc, NULL);
- pen = SelectObject(plot_hdc, penbak);
- DeleteObject(clipregion);
- DeleteObject(pen);
-
- return true;
-}
-
-static bool
+/**
+ * bitmap helper to plot a solid block of colour
+ *
+ * \param col colour to plot with
+ * \param x the x coordinate to plot at
+ * \param y the y coordinate to plot at
+ * \param width the width of block to plot
+ * \param height the height to plot
+ * \return NSERROR_OK on sucess else error code.
+ */
+static nserror
plot_block(COLORREF col, int x, int y, int width, int height)
{
HRGN clipregion;
@@ -499,24 +73,24 @@ plot_block(COLORREF col, int x, int y, int width, int height)
(y >= plot_clip.bottom) ||
((y + height) < plot_clip.top)) {
/* Image completely outside clip region */
- return true;
- }
+ return NSERROR_OK;
+ }
/* ensure the plot HDC is set */
if (plot_hdc == NULL) {
LOG("HDC not set on call to plotters");
- return false;
+ return NSERROR_INVALID;
}
clipregion = CreateRectRgnIndirect(&plot_clip);
if (clipregion == NULL) {
- return false;
+ return NSERROR_INVALID;
}
SelectClipRgn(plot_hdc, clipregion);
/* Saving the original pen object */
- original = SelectObject(plot_hdc,GetStockObject(DC_PEN));
+ original = SelectObject(plot_hdc,GetStockObject(DC_PEN));
SelectObject(plot_hdc, GetStockObject(DC_PEN));
SelectObject(plot_hdc, GetStockObject(DC_BRUSH));
@@ -528,15 +102,20 @@ plot_block(COLORREF col, int x, int y, int width, int height)
DeleteObject(clipregion);
- return true;
+ return NSERROR_OK;
}
-/* blunt force truma way of achiving alpha blended plotting */
-static bool
-plot_alpha_bitmap(HDC hdc,
- struct bitmap *bitmap,
- int x, int y,
+
+/**
+ * plot an alpha blended bitmap
+ *
+ * blunt force truma way of achiving alpha blended plotting
+ */
+static nserror
+plot_alpha_bitmap(HDC hdc,
+ struct bitmap *bitmap,
+ int x, int y,
int width, int height)
{
#ifdef WINDOWS_GDI_ALPHA_WORKED
@@ -545,15 +124,17 @@ plot_alpha_bitmap(HDC hdc,
bool bltres;
bmihdc = CreateCompatibleDC(hdc);
SelectObject(bmihdc, bitmap->windib);
- bltres = AlphaBlend(hdc,
- x, y,
+ bltres = AlphaBlend(hdc,
+ x, y,
width, height,
bmihdc,
- 0, 0,
+ 0, 0,
bitmap->width, bitmap->height,
blnd);
DeleteDC(bmihdc);
- return bltres;
+ if (!bltres) {
+ return NSERROR_INVALID;
+ }
#else
HDC Memhdc;
BITMAPINFOHEADER bmih;
@@ -569,16 +150,17 @@ plot_alpha_bitmap(HDC hdc,
Memhdc = CreateCompatibleDC(hdc);
if (Memhdc == NULL) {
- return false;
+ return NSERROR_INVALID;
}
- if ((bitmap->width != width) ||
+ if ((bitmap->width != width) ||
(bitmap->height != height)) {
- PLOT_LOG("scaling from %d,%d to %d,%d",
+ PLOT_LOG("scaling from %d,%d to %d,%d",
bitmap->width, bitmap->height, width, height);
bitmap = bitmap_scale(bitmap, width, height);
- if (bitmap == NULL)
- return false;
+ if (bitmap == NULL) {
+ return NSERROR_INVALID;
+ }
isscaled = true;
}
@@ -586,14 +168,14 @@ plot_alpha_bitmap(HDC hdc,
(bitmap->width * bitmap->height * 4));
if (bmi == NULL) {
DeleteDC(Memhdc);
- return false;
+ return NSERROR_INVALID;
}
MemBMh = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height);
if (MemBMh == NULL){
free(bmi);
DeleteDC(Memhdc);
- return false;
+ return NSERROR_INVALID;
}
/* save 'background' data for alpha channel work */
@@ -655,7 +237,7 @@ plot_alpha_bitmap(HDC hdc,
}
}
SetDIBitsToDevice(hdc, x, y, bitmap->width, bitmap->height,
- 0, 0, 0, bitmap->height,
+ 0, 0, 0, bitmap->height,
(const void *) bmi->bmiColors,
bmi, DIB_RGB_COLORS);
@@ -667,16 +249,19 @@ plot_alpha_bitmap(HDC hdc,
free(bmi);
DeleteObject(MemBMh);
DeleteDC(Memhdc);
- return true;
#endif
+
+ return NSERROR_OK;
}
-static bool
+/**
+ */
+static nserror
plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
{
- int bltres;
HRGN clipregion;
+ nserror res = NSERROR_OK;
/* Bail early if we can */
if ((x >= plot_clip.right) ||
@@ -684,25 +269,26 @@ plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
(y >= plot_clip.bottom) ||
((y + height) < plot_clip.top)) {
/* Image completely outside clip region */
- return true;
- }
+ return NSERROR_OK;
+ }
/* ensure the plot HDC is set */
if (plot_hdc == NULL) {
LOG("HDC not set on call to plotters");
- return false;
+ return NSERROR_INVALID;
}
clipregion = CreateRectRgnIndirect(&plot_clip);
if (clipregion == NULL) {
- return false;
+ return NSERROR_INVALID;
}
SelectClipRgn(plot_hdc, clipregion);
if (bitmap->opaque) {
+ int bltres;
/* opaque bitmap */
- if ((bitmap->width == width) &&
+ if ((bitmap->width == width) &&
(bitmap->height == height)) {
/* unscaled */
bltres = SetDIBitsToDevice(plot_hdc,
@@ -717,36 +303,548 @@ plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height)
} else {
/* scaled */
SetStretchBltMode(plot_hdc, COLORONCOLOR);
- bltres = StretchDIBits(plot_hdc,
- x, y,
+ bltres = StretchDIBits(plot_hdc,
+ x, y,
width, height,
- 0, 0,
+ 0, 0,
bitmap->width, bitmap->height,
- bitmap->pixdata,
- (BITMAPINFO *)bitmap->pbmi,
- DIB_RGB_COLORS,
+ bitmap->pixdata,
+ (BITMAPINFO *)bitmap->pbmi,
+ DIB_RGB_COLORS,
SRCCOPY);
}
+ /* check to see if GDI operation failed */
+ if (bltres == 0) {
+ res = NSERROR_INVALID;
+ }
+ PLOT_LOG("bltres = %d", bltres);
} else {
/* Bitmap with alpha.*/
- bltres = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height);
+ res = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height);
+ }
+
+ DeleteObject(clipregion);
+
+ return res;
+}
+
+
+
+
+/**
+ * \brief Sets a clip rectangle for subsequent plot operations.
+ *
+ * \param ctx The current redraw context.
+ * \param clip The rectangle to limit all subsequent plot
+ * operations within.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
+{
+ PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1);
+
+ plot_clip.left = clip->x0;
+ plot_clip.top = clip->y0;
+ plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */
+ plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots an arc
+ *
+ * plot an arc segment around (x,y), anticlockwise from angle1
+ * to angle2. Angles are measured anticlockwise from
+ * horizontal, in degrees.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the arc plot.
+ * \param x The x coordinate of the arc.
+ * \param y The y coordinate of the arc.
+ * \param radius The radius of the arc.
+ * \param angle1 The start angle of the arc.
+ * \param angle2 The finish angle of the arc.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+arc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y,
+ int radius, int angle1, int angle2)
+{
+ PLOT_LOG("arc centre %d,%d radius %d from %d to %d", x, y, radius,
+ angle1, angle2);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+
+ int q1, q2;
+ double a1=1.0, a2=1.0, b1=1.0, b2=1.0;
+ q1 = (int) ((angle1 + 45) / 90) - 45;
+ q2 = (int) ((angle2 + 45) / 90) - 45;
+ while (q1 > 4)
+ q1 -= 4;
+ while (q2 > 4)
+ q2 -= 4;
+ while (q1 <= 0)
+ q1 += 4;
+ while (q2 <= 0)
+ q2 += 4;
+ angle1 = ((angle1 + 45) % 90) - 45;
+ angle2 = ((angle2 + 45) % 90) - 45;
+
+ switch(q1) {
+ case 1:
+ a1 = 1.0;
+ b1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 2:
+ b1 = -1.0;
+ a1 = -tan((M_PI / 180) * angle1);
+ break;
+ case 3:
+ a1 = -1.0;
+ b1 = tan((M_PI / 180) * angle1);
+ break;
+ case 4:
+ b1 = 1.0;
+ a1 = tan((M_PI / 180) * angle1);
+ break;
+ }
+
+ switch(q2) {
+ case 1:
+ a2 = 1.0;
+ b2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 2:
+ b2 = -1.0;
+ a2 = -tan((M_PI / 180) * angle2);
+ break;
+ case 3:
+ a2 = -1.0;
+ b2 = tan((M_PI / 180) * angle2);
+ break;
+ case 4:
+ b2 = 1.0;
+ a2 = tan((M_PI / 180) * angle2);
+ break;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x + (int)(a1 * radius), y + (int)(b1 * radius),
+ x + (int)(a2 * radius), y + (int)(b2 * radius));
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a circle
+ *
+ * Plot a circle centered on (x,y), which is optionally filled.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the circle plot.
+ * \param x x coordinate of circle centre.
+ * \param y y coordinate of circle centre.
+ * \param radius circle radius.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+disc(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ int x, int y, int radius)
+{
+ PLOT_LOG("disc at %d,%d radius %d", x, y, radius);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour)
+ & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateSolidBrush(col);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (style->fill_type == PLOT_OP_TYPE_NONE) {
+ Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius,
+ x - radius, y - radius,
+ x - radius, y - radius);
+ } else {
+ Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius);
+ }
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a line
+ *
+ * plot a line from (x0,y0) to (x1,y1). Coordinates are at
+ * centre of line width/thickness.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the line plot.
+ * \param line A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+line(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *line)
+{
+ PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ /* windows 0x00bbggrr */
+ DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type ==
+ PLOT_OP_TYPE_DOT) ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH:
+ 0);
+ LOGBRUSH lb = {BS_SOLID, col, 0};
+ HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (bak == NULL) {
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ MoveToEx(plot_hdc, line->x0, line->y0, (LPPOINT) NULL);
+
+ LineTo(plot_hdc, line->x1, line->y1);
+
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, bak);
+
+ DeleteObject(pen);
+ DeleteObject(clipregion);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plots a rectangle.
+ *
+ * The rectangle can be filled an outline or both controlled
+ * by the plot style The line can be solid, dotted or
+ * dashed. Top left corner at (x0,y0) and rectangle has given
+ * width and height.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the rectangle plot.
+ * \param rect A rectangle defining the line to be drawn
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *rect)
+{
+ PLOT_LOG("rectangle from %d,%d to %d,%d",
+ rect->x0, rect->y0, rect->x1, rect->y1);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF);
+ DWORD penstyle = PS_GEOMETRIC |
+ (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT :
+ (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH :
+ (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL :
+ 0)));
+ LOGBRUSH lb = {BS_SOLID, pencol, 0};
+ LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0};
+ if (style->fill_type == PLOT_OP_TYPE_NONE)
+ lb1.lbStyle = BS_HOLLOW;
+
+ HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL);
+ if (pen == NULL) {
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen);
+ if (penbak == NULL) {
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateBrushIndirect(&lb1);
+ if (brush == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush);
+ if (brushbak == NULL) {
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ /* windows GDI call coordinates are inclusive */
+ Rectangle(plot_hdc, rect->x0, rect->y0, rect->x1 + 1, rect->y1 + 1);
+
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
+ SelectClipRgn(plot_hdc, NULL);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ DeleteObject(clipregion);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Plot a polygon
+ *
+ * Plots a filled polygon with straight lines between
+ * points. The lines around the edge of the ploygon are not
+ * plotted. The polygon is filled with the non-zero winding
+ * rule.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the polygon plot.
+ * \param p verticies of polygon
+ * \param n number of verticies.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+polygon(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const int *p,
+ unsigned int n)
+{
+ PLOT_LOG("polygon %d points", n);
+
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ POINT points[n];
+ unsigned int i;
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF);
+ HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol);
+ if (pen == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ HPEN penbak = SelectObject(plot_hdc, pen);
+ if (penbak == NULL) {
+ DeleteObject(clipregion);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brush = CreateSolidBrush(brushcol);
+ if (brush == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ return NSERROR_INVALID;
+ }
+ HBRUSH brushbak = SelectObject(plot_hdc, brush);
+ if (brushbak == NULL) {
+ DeleteObject(clipregion);
+ SelectObject(plot_hdc, penbak);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ return NSERROR_INVALID;
+ }
+ SetPolyFillMode(plot_hdc, WINDING);
+ for (i = 0; i < n; i++) {
+ points[i].x = (long) p[2 * i];
+ points[i].y = (long) p[2 * i + 1];
+
+ PLOT_LOG("%ld,%ld ", points[i].x, points[i].y);
+ }
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ if (n >= 2) {
+ Polygon(plot_hdc, points, n);
}
- PLOT_LOG("bltres = %d", bltres);
+ SelectClipRgn(plot_hdc, NULL);
+ pen = SelectObject(plot_hdc, penbak);
+ brush = SelectObject(plot_hdc, brushbak);
DeleteObject(clipregion);
+ DeleteObject(pen);
+ DeleteObject(brush);
+
+ return NSERROR_OK;
+}
- return true;
+/**
+ * Plots a path.
+ *
+ * Path plot consisting of cubic Bezier curves. Line and fill colour is
+ * controlled by the plot style.
+ *
+ * \param ctx The current redraw context.
+ * \param pstyle Style controlling the path plot.
+ * \param p elements of path
+ * \param n nunber of elements on path
+ * \param width The width of the path
+ * \param transform A transform to apply to the path.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+path(const struct redraw_context *ctx,
+ const plot_style_t *pstyle,
+ const float *p,
+ unsigned int n,
+ float width,
+ const float transform[6])
+{
+ PLOT_LOG("path unimplemented");
+ return NSERROR_OK;
}
-static bool
-windows_plot_bitmap(int x, int y,
- int width, int height,
- struct bitmap *bitmap, colour bg,
- bitmap_flags_t flags)
+
+/**
+ * Plot a bitmap
+ *
+ * Tiled plot of a bitmap image. (x,y) gives the top left
+ * coordinate of an explicitly placed tile. From this tile the
+ * image can repeat in all four directions -- up, down, left
+ * and right -- to the extents given by the current clip
+ * rectangle.
+ *
+ * The bitmap_flags say whether to tile in the x and y
+ * directions. If not tiling in x or y directions, the single
+ * image is plotted. The width and height give the dimensions
+ * the image is to be scaled to.
+ *
+ * \param ctx The current redraw context.
+ * \param bitmap The bitmap to plot
+ * \param x The x coordinate to plot the bitmap
+ * \param y The y coordiante to plot the bitmap
+ * \param width The width of area to plot the bitmap into
+ * \param height The height of area to plot the bitmap into
+ * \param bg the background colour to alpha blend into
+ * \param flags the flags controlling the type of plot operation
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+bitmap(const struct redraw_context *ctx,
+ struct bitmap *bitmap,
+ int x, int y,
+ int width,
+ int height,
+ colour bg,
+ bitmap_flags_t flags)
{
int xf,yf;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
@@ -758,12 +856,12 @@ windows_plot_bitmap(int x, int y,
if (bitmap == NULL) {
LOG("Passed null bitmap!");
- return true;
+ return NSERROR_OK;
}
/* check if nothing to plot */
if (width == 0 || height == 0)
- return true;
+ return NSERROR_OK;
/* x and y define coordinate of top left of of the initial explicitly
* placed tile. The width and height are the image scaling and the
@@ -775,7 +873,7 @@ windows_plot_bitmap(int x, int y,
/* Not repeating at all, so just plot it */
if ((bitmap->width == 1) && (bitmap->height == 1)) {
if ((*(bitmap->pixdata + 3) & 0xff) == 0) {
- return true;
+ return NSERROR_OK;
}
return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, x, y, x + width, y + height);
@@ -788,10 +886,10 @@ windows_plot_bitmap(int x, int y,
* of the area. Can only be done when image is fully opaque. */
if ((bitmap->width == 1) && (bitmap->height == 1)) {
if ((*(COLORREF *)bitmap->pixdata & 0xff000000) != 0) {
- return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
- plot_clip.left,
- plot_clip.top,
- plot_clip.right,
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
plot_clip.bottom);
}
}
@@ -803,10 +901,10 @@ windows_plot_bitmap(int x, int y,
if (bitmap->opaque) {
/** TODO: Currently using top left pixel. Maybe centre
* pixel or average value would be better. */
- return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
- plot_clip.left,
- plot_clip.top,
- plot_clip.right,
+ return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff,
+ plot_clip.left,
+ plot_clip.top,
+ plot_clip.right,
plot_clip.bottom);
}
}
@@ -815,12 +913,14 @@ windows_plot_bitmap(int x, int y,
PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom);
/* get left most tile position */
- if (repeat_x)
+ if (repeat_x) {
for (; x > plot_clip.left; x -= width);
+ }
/* get top most tile position */
- if (repeat_y)
+ if (repeat_y) {
for (; y > plot_clip.top; y -= height);
+ }
PLOT_LOG("repeat from %d,%d to %ld,%ld", x, y, plot_clip.right, plot_clip.bottom);
@@ -833,25 +933,86 @@ windows_plot_bitmap(int x, int y,
break;
}
if (!repeat_x)
- break;
+ break;
}
- return true;
+ return NSERROR_OK;
}
-static bool flush(void)
+/**
+ * Text plotting.
+ *
+ * \param ctx The current redraw context.
+ * \param fstyle plot style for this text
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param text UTF-8 string to plot
+ * \param length length of string, in bytes
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+text(const struct redraw_context *ctx,
+ const struct plot_font_style *fstyle,
+ int x,
+ int y,
+ const char *text,
+ size_t length)
{
- PLOT_LOG("flush unimplemented");
- return true;
-}
+ PLOT_LOG("words %s at %d,%d", text, x, y);
-static bool path(const float *p, unsigned int n, colour fill, float width,
- colour c, const float transform[6])
-{
- PLOT_LOG("path unimplemented");
- return true;
+ /* ensure the plot HDC is set */
+ if (plot_hdc == NULL) {
+ LOG("HDC not set on call to plotters");
+ return NSERROR_INVALID;
+ }
+
+ HRGN clipregion = CreateRectRgnIndirect(&plot_clip);
+ if (clipregion == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ HFONT fontbak, font = get_font(fstyle);
+ if (font == NULL) {
+ DeleteObject(clipregion);
+ return NSERROR_INVALID;
+ }
+ int wlen;
+ SIZE s;
+ LPWSTR wstring;
+ fontbak = (HFONT) SelectObject(plot_hdc, font);
+ GetTextExtentPoint(plot_hdc, text, length, &s);
+
+ SelectClipRgn(plot_hdc, clipregion);
+
+ SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT);
+ if ((fstyle->background & 0xFF000000) != 0x01000000) {
+ /* 100% alpha */
+ SetBkColor(plot_hdc, (DWORD) (fstyle->background & 0x00FFFFFF));
+ }
+ SetBkMode(plot_hdc, TRANSPARENT);
+ SetTextColor(plot_hdc, (DWORD) (fstyle->foreground & 0x00FFFFFF));
+
+ wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0);
+ wstring = malloc(2 * (wlen + 1));
+ if (wstring == NULL) {
+ return NSERROR_INVALID;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen);
+ TextOutW(plot_hdc, x, y, wstring, wlen);
+
+ SelectClipRgn(plot_hdc, NULL);
+ free(wstring);
+ font = SelectObject(plot_hdc, fontbak);
+ DeleteObject(clipregion);
+ DeleteObject(font);
+
+ return NSERROR_OK;
}
+
+/**
+ * win32 API plot operation table
+ */
const struct plotter_table win_plotters = {
.rectangle = rectangle,
.line = line,
@@ -860,8 +1021,7 @@ const struct plotter_table win_plotters = {
.text = text,
.disc = disc,
.arc = arc,
- .bitmap = windows_plot_bitmap,
- .flush = flush,
+ .bitmap = bitmap,
.path = path,
.option_knockout = true,
};