#include "win32\win32guts.h" #ifndef _APRICOT_H_ #include "apricot.h" #endif #include "guts.h" #include "Window.h" #include "Icon.h" #include "DeviceBitmap.h" #ifdef __cplusplus extern "C" { #endif #define sys (( PDrawableData)(( PComponent) self)-> sysData)-> #define dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)-> #define var (( PWidget) self)-> #define HANDLE sys handle #define DHANDLE(x) dsys(x) handle static Bool create_gdip_surface(Handle self) { HRGN rgn; /* force null region as it lingers in GDI+ space somehow */ rgn = CreateRectRgn(0,0,0,0); if ( GetClipRgn( sys ps, rgn ) > 0 ) SelectClipRgn( sys ps, NULL); else rgn = NULL; GPCALL GdipCreateFromHDC(sys ps, &sys graphics); apiGPErrCheckRet(false); if ( rgn ) { SelectClipRgn( sys ps, rgn); GPCALL GdipSetClipHrgn(sys graphics, rgn, CombineModeReplace); apiGPErrCheck; DeleteObject( rgn); } return true; } #define CREATE_GDIP_SURFACE (( sys ps && sys graphics == NULL ) ? create_gdip_surface(self) : true) Bool apc_gp_set_alpha( Handle self, int alpha) { if ( ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) || ( is_apt(aptImage) && ((PImage)self)-> type == imBW ) ) alpha = 255; sys alpha = alpha; if ( alpha < 255 ) { if ( !CREATE_GDIP_SURFACE) { sys alpha = 255; return false; } } if ( sys ps && sys graphics ) stylus_change( self); if ( sys alphaArenaPalette ) { free(sys alphaArenaPalette); sys alphaArenaPalette = NULL; } return true; } Bool apc_gp_set_antialias( Handle self, Bool aa) { if ( aa ) { if ( ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) || ( is_apt(aptImage) && ((PImage)self)-> type == imBW ) ) return false; if ( !CREATE_GDIP_SURFACE) return false; apt_set(aptGDIPlus); GdipSetSmoothingMode(sys graphics, SmoothingModeAntiAlias); GdipSetPixelOffsetMode(sys graphics, PixelOffsetModeHalf); } else { apt_clear(aptGDIPlus); GdipSetSmoothingMode(sys graphics, SmoothingModeNone); GdipSetPixelOffsetMode(sys graphics, PixelOffsetModeNone); } return true; } int apc_gp_get_alpha( Handle self) { return sys alpha; } Bool apc_gp_get_antialias( Handle self) { return is_apt(aptGDIPlus); } Bool apc_gp_aa_bar( Handle self, double x1, double y1, double x2, double y2) { double dy = sys lastSize. y; Point t = sys gp_transform; objCheck false; x2 -= x1 - 1; y2 -= y1 - 1; x1 += t.x; y1 = t.y + dy - y1 - y2; STYLUS_USE_GP_BRUSH; GPCALL GdipFillRectangle( sys graphics, sys stylusGPResource-> brush, x1, y1, x2, y2 ); apiGPErrCheckRet(false); return true; } Bool apc_gp_aa_fill_poly( Handle self, int numPts, NPoint * points) { int i; double dy = sys lastSize. y; Point t = sys gp_transform; GpPointF *p; objCheck false; if ((p = malloc( sizeof(GpPointF) * numPts)) == NULL) return false; for ( i = 0; i < numPts; i++) { p[i].X = t.x + points[i].x; p[i].Y = t.y + dy - points[i].y; } STYLUS_USE_GP_BRUSH; GPCALL GdipFillPolygon( sys graphics, sys stylusGPResource-> brush, p, numPts, ((sys psFillMode & fmWinding) == fmAlternate) ? FillModeAlternate : FillModeWinding ); apiGPErrCheckRet(false); return true; } /* emulate alpha text */ #define GRAD 57.29577951 void aa_free_arena(Handle self, Bool for_reuse) { if ( !for_reuse && sys alphaArenaPalette ) { free(sys alphaArenaPalette); sys alphaArenaPalette = NULL; } if ( !sys alphaArenaDC) return; if (sys alphaArenaStockFont) SelectObject( sys alphaArenaDC, sys alphaArenaStockFont); SelectObject( sys alphaArenaDC, sys alphaArenaStockBitmap); DeleteObject( sys alphaArenaBitmap ); sys alphaArenaBitmap = NULL; sys alphaArenaStockFont = NULL; sys alphaArenaStockBitmap = NULL; if ( !for_reuse ) { DeleteDC(sys alphaArenaDC); sys alphaArenaDC = NULL; } } static Bool aa_make_arena(Handle self) { int w,h; w = var font. maximalWidth; h = var font. height; if ( w < h ) w = h; if ( var font. direction != 0) { if ( sys font_sin == sys font_cos && sys font_sin == 0.0 ) { sys font_sin = sin( var font. direction / GRAD); sys font_cos = cos( var font. direction / GRAD); } } if ( w < sys alphaArenaSize.x || h < sys alphaArenaSize.y || !sys alphaArenaDC ) { HDC dc; if ( sys alphaArenaBitmap ) { aa_free_arena(self, true); } else { if (!( sys alphaArenaDC = CreateCompatibleDC(0))) return false; SetTextAlign(sys alphaArenaDC, TA_BOTTOM); SetBkMode( sys alphaArenaDC, TRANSPARENT); SetTextColor( sys alphaArenaDC, 0xffffff); } sys alphaArenaSize.x = sys alphaArenaSize.y = w * 4; dc = dc_alloc(); if ( !( sys alphaArenaBitmap = image_create_argb_dib_section( dc, sys alphaArenaSize.x, sys alphaArenaSize.y, &sys alphaArenaPtr ))) { dc_free(); return false; } dc_free(); sys alphaArenaStockBitmap = SelectObject( sys alphaArenaDC, sys alphaArenaBitmap); sys alphaArenaStockFont = NULL; sys alphaArenaFontChanged = true; } if ( sys alphaArenaFontChanged || !sys alphaArenaStockFont) { HFONT f; f = SelectObject( sys alphaArenaDC, sys fontResource-> hfont ); if ( !sys alphaArenaStockFont ) sys alphaArenaStockFont = f; sys alphaArenaFontChanged = false; } return true; } static Bool aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance, int dx, int dy) { BLENDFUNCTION bf; float xx, yy, shift; register uint32_t * p, * palette; int i, j, miny, maxy, maxx, minx; Point sz; /* replace white to our color + alpha, calculate minimal affected box */ p = sys alphaArenaPtr; palette = sys alphaArenaPalette; for ( i = maxy = maxx = 0, minx = sys alphaArenaSize.x - 1, miny = sys alphaArenaSize.y - 1; i < sys alphaArenaSize.y; i++ ) { Bool match = false; for ( j = 0; j < sys alphaArenaSize.x; j++, p++) { if (1 || *p != 0) { register Byte *argb = (Byte*) p; *p = palette[argb[0] + argb[1] + argb[2]]; if ( minx > j ) minx = j; if ( maxx < j ) maxx = j; match = true; } } if ( match ) { if ( miny > i ) miny = i; if ( maxy < i ) maxy = i; } } if ( maxy < miny ) return true; /* calculate advance for the next glyph and the position, if needed, for this one */ if ( advance >= 0 ) { shift = advance; if ( var font.direction != 0 ) { xx = (dx * sys font_cos) - (dy * sys font_sin); yy = (dx * sys font_sin) + (dy * sys font_cos); } else { xx = dx; yy = dy; } } else { shift = abc->abcfA + abc->abcfB + abc->abcfC; xx = yy = 0.0; } x += round(delta->x + xx); y += round(delta->y - yy); if ( var font.direction != 0 ) { delta->x += shift * sys font_cos; delta->y -= shift * sys font_sin; } else { delta->x += shift; } /* calculate the aperture */ sz = sys alphaArenaSize; x -= sz.x/2; y -= sz.y/2; if ( is_apt( aptTextOutBaseline)) { if ( var font. direction != 0 ) { float d = var font. descent; x += d * sys font_sin + .5; y += d * sys font_cos + .5; } else y += var font. descent; } /* minimize the blit rectangle */ { int m, n; m = sys alphaArenaSize.y - maxy - 1; n = sys alphaArenaSize.y - miny - 1; miny = m; maxy = n; } sz.x = maxx - minx + 1; sz.y = maxy - miny + 1; /* blend */ bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 0xff; bf.AlphaFormat = AC_SRC_ALPHA; return AlphaBlend( sys ps, x + minx, y + miny, sz.x, sz.y, sys alphaArenaDC, minx, miny, sz.x, sz.y, bf); } /* precalculate alpha map */ Bool aa_fill_palette(Handle self) { int i,j,r,g,b; PStylus s = & sys stylus; if ( sys alphaArenaPalette ) return true; if ( !( sys alphaArenaPalette = malloc(4 * 256 * 3))) return false; b = (s->pen.lopnColor >> 16) & 0xff; g = (s->pen.lopnColor & 0xff00) >> 8; r = s->pen.lopnColor & 0xff; for ( i = j = 0; i < 256; i++) { uint32_t a = sys alpha * i / 255; a = (a << 24) | ((r * a / 255 ) << 16) | ((g * a / 255 ) << 8) | ( b * a / 255 ) ; sys alphaArenaPalette[j++] = a; sys alphaArenaPalette[j++] = a; sys alphaArenaPalette[j++] = a; } return true; } Bool aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide) { int i; NPoint delta = { 0, 0 }; if ( !(aa_fill_palette(self) && aa_make_arena(self))) return false; for ( i = 0; i < len; i++) { ABCFLOAT abc; memset(sys alphaArenaPtr, 0, sys alphaArenaSize.x * sys alphaArenaSize.y * 4); if ( wide ) { if (!GetCharABCWidthsFloatW( sys ps, ((WCHAR*)text)[i], ((WCHAR*)text)[i], &abc)) apiErrRet; } else { if (!GetCharABCWidthsFloatA( sys ps, ((char *)text)[i], ((char *)text)[i], &abc)) apiErrRet; } if ( wide ) { if (!TextOutW( sys alphaArenaDC, sys alphaArenaSize.x/2, sys alphaArenaSize.y/2, ((WCHAR*)text) + i, 1)) apiErrRet; } else { if (!TextOutA( sys alphaArenaDC, sys alphaArenaSize.x/2, sys alphaArenaSize.y/2, ((char *)text) + i, 1)) apiErrRet; } if ( !aa_render(self, x, y, &delta, &abc, -1, 0, 0)) return false; } return true; } Bool aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font) { int i; NPoint delta = { 0, 0 }; uint16_t *advances = t->advances; int16_t *positions = t->positions; HFONT f; if ( !(aa_fill_palette(self) && aa_make_arena(self))) return false; if ( text_advance ) *text_advance = 0; f = SelectObject( sys alphaArenaDC, font ); if ( !sys alphaArenaStockFont ) sys alphaArenaStockFont = f; sys alphaArenaFontChanged = false; for ( i = 0; i < t->len; i++) { ABCFLOAT abc, *pabc; int adv, dx, dy; memset(sys alphaArenaPtr, 0, sys alphaArenaSize.x * sys alphaArenaSize.y * 4); if ( !ExtTextOutW(sys alphaArenaDC, sys alphaArenaSize.x/2, sys alphaArenaSize.y/2, ETO_GLYPH_INDEX, NULL, (LPCWSTR)(t->glyphs) + i, 1, NULL )) apiErrRet; if ( advances ) { adv = *(advances++); if ( text_advance ) *text_advance += adv; pabc = NULL; dx = *(positions++); dy = *(positions++); } else { ABC abci; adv = -1; pabc = &abc; dx = dy = 0; if (!GetCharABCWidthsI( sys ps, ((WCHAR*)(t->glyphs))[i], 1, NULL, &abci)) apiErr; if ( text_advance ) *text_advance += abci.abcA + abci.abcB + abci.abcC; abc.abcfA = abci.abcA; abc.abcfB = abci.abcB; abc.abcfC = abci.abcC; } if ( !aa_render(self, x, y, &delta, pabc, adv, dx, dy)) return false; } return true; } #ifdef __cplusplus } #endif