diff options
Diffstat (limited to 'Src/tataki/canvas')
-rw-r--r-- | Src/tataki/canvas/PaintCanvas.h | 3 | ||||
-rw-r--r-- | Src/tataki/canvas/bltcanvas.h | 5 | ||||
-rw-r--r-- | Src/tataki/canvas/canvas.h | 5 | ||||
-rw-r--r-- | Src/tataki/canvas/ifc_canvas.cpp | 1 | ||||
-rw-r--r-- | Src/tataki/canvas/ifc_canvas.h | 165 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/PaintCanvas.cpp | 51 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/PaintCanvas.h | 46 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/bltcanvas.h | 27 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/canvas.h | 70 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/osx_canvas_layer.cpp | 95 | ||||
-rw-r--r-- | Src/tataki/canvas/mac/osx_canvas_quartz.cpp | 275 | ||||
-rw-r--r-- | Src/tataki/canvas/win/BltCanvas.cpp | 295 | ||||
-rw-r--r-- | Src/tataki/canvas/win/bltcanvas.h | 41 | ||||
-rw-r--r-- | Src/tataki/canvas/win/canvas.h | 368 | ||||
-rw-r--r-- | Src/tataki/canvas/win/win32_canvas.cpp | 1489 |
15 files changed, 2936 insertions, 0 deletions
diff --git a/Src/tataki/canvas/PaintCanvas.h b/Src/tataki/canvas/PaintCanvas.h new file mode 100644 index 00000000..f32e74e4 --- /dev/null +++ b/Src/tataki/canvas/PaintCanvas.h @@ -0,0 +1,3 @@ +#ifdef __APPLE__ +#include "mac/PaintCanvas.h" +#endif
\ No newline at end of file diff --git a/Src/tataki/canvas/bltcanvas.h b/Src/tataki/canvas/bltcanvas.h new file mode 100644 index 00000000..6ffa07a5 --- /dev/null +++ b/Src/tataki/canvas/bltcanvas.h @@ -0,0 +1,5 @@ +#ifdef _WIN32 +#include "win/bltcanvas.h" +#elif defined(__APPLE__) +#include "mac/bltcanvas.h" +#endif diff --git a/Src/tataki/canvas/canvas.h b/Src/tataki/canvas/canvas.h new file mode 100644 index 00000000..b645a654 --- /dev/null +++ b/Src/tataki/canvas/canvas.h @@ -0,0 +1,5 @@ +#ifdef _WIN32 +#include "win/canvas.h" +#elif defined(__APPLE__) +#include "mac/canvas.h" +#endif
\ No newline at end of file diff --git a/Src/tataki/canvas/ifc_canvas.cpp b/Src/tataki/canvas/ifc_canvas.cpp new file mode 100644 index 00000000..b209c9de --- /dev/null +++ b/Src/tataki/canvas/ifc_canvas.cpp @@ -0,0 +1 @@ +#include "ifc_canvas.h"
\ No newline at end of file diff --git a/Src/tataki/canvas/ifc_canvas.h b/Src/tataki/canvas/ifc_canvas.h new file mode 100644 index 00000000..6c7796cf --- /dev/null +++ b/Src/tataki/canvas/ifc_canvas.h @@ -0,0 +1,165 @@ +#ifndef NULLSOFT_TATAKI_IFC_CANVAS_H +#define NULLSOFT_TATAKI_IFC_CANVAS_H + +#include <bfc/dispatch.h> +#include <bfc/platform/platform.h> +#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later +#include <bfc/wasabi_std.h> // for WASABI_DEFAULT_FONTNAMEW + +namespace Wasabi +{ + // benski> move this to std_font later +struct FontInfo +{ + FontInfo() + { + // defaults + face = WASABI_DEFAULT_FONTNAMEW; + pointSize = 12; + bold = 0; + opaque = false; + underline = false; + italic = false; + alignFlags = STDFONT_LEFT; + antialias = 1; + bgColor = RGBA(255, 255, 255, 255); + color = RGBA(0, 0, 0, 0); + } + + const wchar_t *face; + unsigned int pointSize; + int bold; // bold level + bool opaque; + bool underline; + bool italic; + int alignFlags; + int antialias; // anti-alias level + ARGB32 color; + ARGB32 bgColor; +}; +} + +class ifc_window; +// abstract base class: safe to use in API +class NOVTABLE ifc_canvas : public Dispatchable +{ +protected: + ifc_canvas() + {} // protect constructor + ~ifc_canvas() + {} + +public: + DISPATCH_CODES + { + GETHDC = 100, + GETROOTWND = 200, + GETBITS = 300, + GETOFFSETS = 400, + ISFIXEDCOORDS = 500, + GETDIM = 600, + GETTEXTFONT = 700, + GETTEXTSIZE = 710, + GETTEXTBOLD = 720, + GETTEXTOPAQUE = 730, + GETTEXTALIGN = 740, + GETTEXTCOLOR = 750, + GETTEXTBKCOLOR = 760, + GETTEXTAA = 770, + GETTEXTUNDERLINE = 780, + GETTEXTITALIC = 790, + GETCLIPBOX = 800, + }; +public: + HDC getHDC(); + ifc_window *getRootWnd(); + void *getBits(); + void getOffsets(int *x, int *y); + bool isFixedCoords(); //FG> allows onPaint to handle double buffers as well as normal DCs + bool getDim(int *w, int *h = NULL, int *p = NULL); // w & h in pixels, pitch in bytes. 0 on success. + int getClipBox(RECT *r); // returns 0 if no clipping region + const wchar_t *getTextFont(); + int getTextSize(); + int getTextBold(); + int getTextAntialias(); + int getTextOpaque(); + int getTextUnderline(); + int getTextItalic(); + int getTextAlign(); + ARGB32 getTextColor(); + ARGB32 getTextBkColor(); +}; + + +inline HDC ifc_canvas::getHDC() +{ + return _call(ifc_canvas::GETHDC, (HDC)0); +} +inline ifc_window *ifc_canvas::getRootWnd() +{ + return _call(ifc_canvas::GETROOTWND, (ifc_window*)0); +} +inline void *ifc_canvas::getBits() +{ + return _call(ifc_canvas::GETBITS, (void *)0); +} +inline void ifc_canvas::getOffsets(int *x, int *y) +{ + _voidcall(ifc_canvas::GETOFFSETS, x, y); +} +inline bool ifc_canvas::isFixedCoords() +{ //FG> allows onPaint to handle double buffers as well as normal DCs + return _call(ifc_canvas::ISFIXEDCOORDS, false); +} +inline bool ifc_canvas::getDim(int *w, int *h, int *p) +{ // w & h in pixels, pitch in bytes. 0 on success. + return _call(ifc_canvas::GETDIM, false, w, h, p); +} +inline int ifc_canvas::getClipBox(RECT *r) +{ // returns 0 if no clipping region + return _call(ifc_canvas::GETCLIPBOX, 0, r); +} + +inline const wchar_t *ifc_canvas::getTextFont() +{ + return _call(ifc_canvas::GETTEXTFONT, L""); +} +inline int ifc_canvas::getTextSize() +{ + return _call(ifc_canvas::GETTEXTSIZE, -1); +} +inline int ifc_canvas::getTextBold() +{ + return _call(ifc_canvas::GETTEXTBOLD, 0); +} +inline int ifc_canvas::getTextAntialias() +{ + return _call(ifc_canvas::GETTEXTAA, 0); +} +inline int ifc_canvas::getTextOpaque() +{ + return _call(ifc_canvas::GETTEXTOPAQUE, 0); +} +inline int ifc_canvas::getTextUnderline() +{ + return _call(ifc_canvas::GETTEXTUNDERLINE, 0); +} +inline int ifc_canvas::getTextItalic() +{ + return _call(ifc_canvas::GETTEXTITALIC, 0); +} +inline int ifc_canvas::getTextAlign() +{ + return _call(ifc_canvas::GETTEXTALIGN, -1); +} +inline ARGB32 ifc_canvas::getTextColor() +{ + return _call(ifc_canvas::GETTEXTCOLOR, RGB(0, 0, 0)); +} +inline ARGB32 ifc_canvas::getTextBkColor() +{ + return _call(ifc_canvas::GETTEXTBKCOLOR, RGB(255, 255, 255)); +} + +typedef ifc_canvas api_canvas; +#endif diff --git a/Src/tataki/canvas/mac/PaintCanvas.cpp b/Src/tataki/canvas/mac/PaintCanvas.cpp new file mode 100644 index 00000000..6cfeb126 --- /dev/null +++ b/Src/tataki/canvas/mac/PaintCanvas.cpp @@ -0,0 +1,51 @@ +#include "PaintCanvas.h" + +PaintCanvas::PaintCanvas() +{ + qdcontext=0; +} + +bool PaintCanvas::beginPaint(BaseWnd *wnd) +{ + HIWindowRef macWnd = wnd->getOsWindowHandle(); + + qdcontext = GetWindowPort(macWnd); + QDBeginCGContext(qdcontext, &context); + + return true; +} + +PaintCanvas::~PaintCanvas() +{ + if (qdcontext) + QDEndCGContext(qdcontext, &context); +} + +WndCanvas::WndCanvas() +{ + qdcontext=0; +} + +WndCanvas::~WndCanvas() +{ + if (qdcontext) + QDEndCGContext(qdcontext, &context); +} + +int WndCanvas::attachToClient(BaseWnd *basewnd) +{ + HIWindowRef macWnd = basewnd->getOsWindowHandle(); + + qdcontext = GetWindowPort(macWnd); + QDBeginCGContext(qdcontext, &context); + return 1; +} + + +TextInfoCanvas::TextInfoCanvas(BaseWnd */*unused*/) +{ +} + +TextInfoCanvas::~TextInfoCanvas() +{ +} diff --git a/Src/tataki/canvas/mac/PaintCanvas.h b/Src/tataki/canvas/mac/PaintCanvas.h new file mode 100644 index 00000000..58379508 --- /dev/null +++ b/Src/tataki/canvas/mac/PaintCanvas.h @@ -0,0 +1,46 @@ +#ifndef NULLSOFT_WASABI_OSX_PAINTCANVAS_H +#define NULLSOFT_WASABI_OSX_PAINTCANVAS_H + +#include <tataki/export.h> +#include <tataki/canvas/canvas.h> +#include <api/wnd/basewnd.h> + +class TATAKIAPI PaintCanvas : public Canvas +{ +public: + PaintCanvas(); + ~PaintCanvas(); + bool beginPaint(BaseWnd *wnd); +protected: + CGrafPtr qdcontext; +}; + +class TATAKIAPI PaintBltCanvas : public PaintCanvas +{ +public: + bool beginPaintNC(BaseWnd *wnd) + { + return beginPaint(wnd); + } +}; +#warning port PaintBltCanvas +class TATAKIAPI WndCanvas : public Canvas +{ +public: + WndCanvas(); + virtual ~WndCanvas(); + + // address client area + int attachToClient(BaseWnd *basewnd); + +private: + CGrafPtr qdcontext; +}; + +class TATAKIAPI TextInfoCanvas : public Canvas +{ +public: + TextInfoCanvas(BaseWnd *baseWnd); + virtual ~TextInfoCanvas(); +}; +#endif
\ No newline at end of file diff --git a/Src/tataki/canvas/mac/bltcanvas.h b/Src/tataki/canvas/mac/bltcanvas.h new file mode 100644 index 00000000..e1005dc8 --- /dev/null +++ b/Src/tataki/canvas/mac/bltcanvas.h @@ -0,0 +1,27 @@ +#ifndef _BLTCANVAS_H +#define _BLTCANVAS_H + +#include <tataki/export.h> +#include "canvas.h" + +class TATAKIAPI BltCanvas : public Canvas +{ +public: + BltCanvas(); + BltCanvas(int width, int height, OSWINDOWHANDLE wnd); + + // override blit and stretchblit so we can use CGContextDrawLayerAtPoint/CGContextDrawLayerInRect + virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + void blitToRect(api_canvas *canvas, RECT *src, RECT *dst, int alpha = 255); + + virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + void stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha = 255); + + void DestructiveResize(int w, int h, int nb_bpp = 32); // resizes the bitmap, destroying the contents + void fillBits(ARGB32 color); + +protected: + CGLayerRef layer; +}; + +#endif diff --git a/Src/tataki/canvas/mac/canvas.h b/Src/tataki/canvas/mac/canvas.h new file mode 100644 index 00000000..5258af4e --- /dev/null +++ b/Src/tataki/canvas/mac/canvas.h @@ -0,0 +1,70 @@ +#ifndef NULLSOFT_WASABI_CANVAS_H +#define NULLSOFT_WASABI_CANVAS_H + +#include <tataki/export.h> +#include <Carbon/Carbon.h> +#include <tataki/canvas/api_canvas.h> +#include <bfc/platform/platform.h> +#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later +#include <bfc/std.h> // for WASABI_DEFAULT_FONTNAMEW +class BaseWnd; +class api_region; + +class TATAKIAPI Canvas : public api_canvas +{ +public: + Canvas() :context(0), wnd(0) {} + Canvas(CGContextRef _context) : context(_context), wnd(0) {} + Canvas(CGrafPtr _context); + HDC getHDC(); + void fillRect(const RECT *r, RGB32 color); + void fillRgn(api_region *r, RGB32 color); + void setBaseWnd(BaseWnd *_wnd) { wnd=_wnd; } + void selectClipRgn(api_region *r); + + virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + + void textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + + static float getSystemFontScale() { return 1.0f; } + + int getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo); + int getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo); + int getTextHeight(const Wasabi::FontInfo *fontInfo) + { + return getTextHeight(L"M", fontInfo); + } + void getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo); + void textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + + void drawSysObject(const RECT *r, int sysobj, int alpha=255); +protected: + RECVS_DISPATCH; + + CGContextRef context; + BaseWnd *wnd; // TODO: not 100% sure we'll need this. win32 version has it so we'll keep it for now +}; + +class TATAKIAPI BaseCloneCanvas : public Canvas +{ +public: + BaseCloneCanvas(api_canvas *cloner=NULL); + virtual ~BaseCloneCanvas(); + + int clone(api_canvas *cloner); +}; + +namespace DrawSysObj { + enum { + BUTTON, BUTTON_PUSHED, BUTTON_DISABLED, + OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED, + OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED, + OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED, + OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED, + }; +}; + +#endif diff --git a/Src/tataki/canvas/mac/osx_canvas_layer.cpp b/Src/tataki/canvas/mac/osx_canvas_layer.cpp new file mode 100644 index 00000000..c6f80347 --- /dev/null +++ b/Src/tataki/canvas/mac/osx_canvas_layer.cpp @@ -0,0 +1,95 @@ +#include <tataki/canvas/bltcanvas.h> + +inline float QuartzBlue(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[0] / 255.f; +} + +inline float QuartzGreen(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[1] / 255.f; +} + +inline float QuartzRed(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[2] / 255.f; +} + +inline float QuartzAlpha(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[3] / 255.f; +} + +BltCanvas::BltCanvas(int width, int height, OSWINDOWHANDLE wnd) +{ + CGrafPtr qdcontext = GetWindowPort(wnd); + CGContextRef temp; + QDBeginCGContext(qdcontext, &temp); + CGSize size = CGSizeMake(width, height); + layer = CGLayerCreateWithContext(temp, size, NULL); + context = CGLayerGetContext(layer); + QDEndCGContext(qdcontext, &temp); +} + +void BltCanvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + CGPoint point = CGPointMake(dstx-srcx, dsty-srcy); + CGContextDrawLayerAtPoint(dest->getHDC(), point, layer); +} + +void BltCanvas::blitToRect(api_canvas *canvas, RECT *src, RECT *dst, int alpha) +{ + CGContextRef dest = canvas->getHDC(); + CGContextSaveGState(dest); + CGContextSetAlpha(dest, (float)alpha/255.f); + // TODO: deal with width properly + CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top); + CGContextDrawLayerInRect(dest, rect, layer); + CGContextRestoreGState(dest); +} + +void BltCanvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + CGContextSaveGState(context); + CGContextTranslateCTM(context, srcx, srcy); + CGRect rect = CGRectMake(dstx, dsty, dstw, dsth); + CGContextDrawLayerInRect(dest->getHDC(), rect, layer); + CGContextRestoreGState(context); +} + +void BltCanvas::stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha) +{ + CGContextRef dest = canvas->getHDC(); + CGContextSaveGState(dest); + CGContextSetAlpha(dest, (float)alpha/255.f); +// TODO: deal with width properly + CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top); + CGContextDrawLayerInRect(dest, rect, layer); + CGContextRestoreGState(dest); +} + +void BltCanvas::DestructiveResize(int w, int h, int nb_bpp) +{ + CGSize size = CGSizeMake(w, h); + CGLayerRef newlayer = CGLayerCreateWithContext(context, size, NULL); + CGContextRelease(context); + CGLayerRelease(layer); + layer = newlayer; + context = CGLayerGetContext(layer); +} + +void BltCanvas::fillBits(ARGB32 color) +{ + CGContextSetRGBFillColor(context, + QuartzRed(color), // red + QuartzGreen(color), // green + QuartzBlue(color), // blue + QuartzAlpha(color) // alpha + ); + + CGContextFillRect(context, CGRectInfinite); +}
\ No newline at end of file diff --git a/Src/tataki/canvas/mac/osx_canvas_quartz.cpp b/Src/tataki/canvas/mac/osx_canvas_quartz.cpp new file mode 100644 index 00000000..dcbae59f --- /dev/null +++ b/Src/tataki/canvas/mac/osx_canvas_quartz.cpp @@ -0,0 +1,275 @@ +#include <bfc/platform/types.h> +#include <Carbon/Carbon.h> +#include <tataki/canvas/canvas.h> +#include <api/wnd/basewnd.h> +#include <tataki/region/api_region.h> + + + +/* various functions that might help out + +for drawSysObject: +HIThemeDrawButton +HIThemeDrawTitleBarWidget for minimize, maximize, exit +*/ + +inline float QuartzBlue(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[0] / 255.f; +} + +inline float QuartzGreen(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[1] / 255.f; + +} + +inline float QuartzRed(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[2] / 255.f; + +} + +inline float QuartzAlpha(RGB32 color) +{ + unsigned char *pixel = (unsigned char *)&color; + return pixel[3] / 255.f; + +} + +Canvas::Canvas(CGrafPtr _context) +{ + +} + +void Canvas::fillRect(const RECT *r, ARGB32 color) +{ + CGContextSetRGBFillColor(context, + QuartzRed(color), // red + QuartzGreen(color), // green + QuartzBlue(color), // blue + QuartzAlpha(color) // alpha + ); + + HIRect rect = HIRectFromRECT(r); + CGContextFillRect(context, rect); +} + +void Canvas::fillRgn(api_region *r, ARGB32 color) +{ + CGContextSetRGBFillColor(context, + QuartzRed(color), // red + QuartzGreen(color), // green + QuartzBlue(color), // blue + QuartzAlpha(color) // alpha + ); + + HIShapeRef shape = r->getOSHandle(); + HIShapeReplacePathInCGContext(shape, context); + CGContextFillPath(context); +} + +void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + // clip dest + // Create CGImage from context + // CGContextDrawImage +} + +HDC Canvas::getHDC() +{ + return context; +} + +void Canvas::selectClipRgn(api_region *r) +{ + if (r) + { + HIShapeRef shape = r->getOSHandle(); + HIShapeReplacePathInCGContext(shape, context); + CGContextClip(context); + } + else + { + CGContextClipToRect(context, CGRectInfinite); + } +} + +void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + // Create CGImage from context + // CGContextDrawImage +} + +void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + // TODO: turn this code into a svc_fontI, and use api_font here instead + size_t len = wcslen(txt); + UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar)); + UniChar *copy = unistr; + while (*txt) + *copy++=*txt++; + *copy=0; + + ATSUStyle style; + ATSUCreateStyle(&style); + + CGContextSaveGState(context); + CGContextSetRGBFillColor(context, + QuartzRed(fontInfo->color), // red + QuartzGreen(fontInfo->color), // green + QuartzBlue(fontInfo->color), // blue + QuartzAlpha(fontInfo->color) // alpha + ); + + ATSUTextLayout layout; + ATSUCreateTextLayout(&layout); + + ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len); + + ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd); + + Rect imageRect; + ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect); + y-=(imageRect.bottom - imageRect.top); + CGContextScaleCTM(context, 1.0, -1.0); + + ATSUAttributeTag tags[] = {kATSUCGContextTag}; + ATSUAttributeValuePtr values[] = {&context}; + ByteCount sizes[] = {sizeof(CGContextRef)}; + ATSUSetLayoutControls(layout, 1, tags, sizes, values); + ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, FloatToFixed(x), FloatToFixed(y)); + ATSUDisposeTextLayout(layout); + ATSUDisposeStyle(style); + CGContextRestoreGState(context); + free(unistr); +} + +void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha) +{ +#warning TODO + using namespace DrawSysObj; + switch(sysobj) + { + case OSBUTTON: + { + HIRect buttonRect = HIRectFromRECT(r); + HIThemeButtonDrawInfo buttonDrawInfo; + buttonDrawInfo.version=0; + buttonDrawInfo.state = kThemeStateActive; + buttonDrawInfo.kind = kThemePushButton; + buttonDrawInfo.value = kThemeButtonOn; + buttonDrawInfo.adornment = kThemeAdornmentNone; + buttonDrawInfo.animation.time.start = 0; + buttonDrawInfo.animation.time.current=0; + HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0); + } + break; + case OSBUTTON_PUSHED: + { + HIRect buttonRect = HIRectFromRECT(r); + HIThemeButtonDrawInfo buttonDrawInfo; + buttonDrawInfo.version=0; + buttonDrawInfo.state = kThemeStatePressed; + buttonDrawInfo.kind = kThemePushButton; + buttonDrawInfo.value = kThemeButtonOn; + buttonDrawInfo.adornment = kThemeAdornmentNone; + buttonDrawInfo.animation.time.start = 0; + buttonDrawInfo.animation.time.current=0; + HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0); + } + break; + case OSBUTTON_DISABLED: + { + HIRect buttonRect = HIRectFromRECT(r); + HIThemeButtonDrawInfo buttonDrawInfo; + buttonDrawInfo.version=0; + buttonDrawInfo.state = kThemeStateInactive; + buttonDrawInfo.kind = kThemePushButton; + buttonDrawInfo.value = kThemeButtonOn; + buttonDrawInfo.adornment = kThemeAdornmentNone; + buttonDrawInfo.animation.time.start = 0; + buttonDrawInfo.animation.time.current=0; + HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0); + } + break; + } +} + +void Canvas::getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo) +{ + // TODO: turn this code into a svc_fontI, and use api_font here instead + size_t len = wcslen(text); + UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar)); + UniChar *copy = unistr; + while (*text) + *copy++=*text++; + *copy=0; + + ATSUStyle style; + ATSUCreateStyle(&style); + + ATSUTextLayout layout; + ATSUCreateTextLayout(&layout); + + ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len); + + ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd); + + Rect imageRect; + ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect); + *h=(imageRect.bottom - imageRect.top); + *w = (imageRect.right - imageRect.left); + + ATSUDisposeTextLayout(layout); + ATSUDisposeStyle(style); + free(unistr); +} + +void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + textOut(r->left, r->top, txt, fontInfo); +} + + +#define CBCLASS Canvas +START_DISPATCH; +CB(GETHDC, getHDC); +END_DISPATCH; +#undef CBCLASS + +BaseCloneCanvas::BaseCloneCanvas(api_canvas *cloner) +{ + if (cloner != NULL) clone(cloner); +} + +int BaseCloneCanvas::clone(api_canvas *cloner) +{ + ASSERTPR(context == NULL, "can't clone twice"); + context = cloner->getHDC(); + CGContextRetain(context); +// bits = cloner->getBits(); +// cloner->getDim(&width, &height, &pitch); + // srcwnd = cloner->getBaseWnd(); +// cloner->getOffsets(&xoffset, &yoffset); +// setTextFont(cloner->getTextFont()); +// setTextSize(cloner->getTextSize()); +// setTextBold(cloner->getTextBold()); +// setTextOpaque(cloner->getTextOpaque()); +// setTextUnderline(cloner->getTextUnderline()); +// setTextItalic(cloner->getTextItalic()); +// setTextAlign(cloner->getTextAlign()); +// setTextColor(cloner->getTextColor()); +// setTextBkColor(cloner->getTextBkColor()); + return (context != NULL); +} + +BaseCloneCanvas::~BaseCloneCanvas() +{ + CGContextRelease(context); + context = NULL; +} + diff --git a/Src/tataki/canvas/win/BltCanvas.cpp b/Src/tataki/canvas/win/BltCanvas.cpp new file mode 100644 index 00000000..5b9a94bc --- /dev/null +++ b/Src/tataki/canvas/win/BltCanvas.cpp @@ -0,0 +1,295 @@ +#include "bltcanvas.h" +#include <tataki/bitmap/bitmap.h> + +BltCanvas::~BltCanvas() +{ + if (hdc == NULL) return ; + + // kill the bitmap and its DC + SelectObject(hdc, prevbmp); + if (ourbmp) + { + //GdiFlush(); + DeleteObject(hbmp); + } + DeleteDC(hdc); + hdc = NULL; + + if (skinbmps) + { + for (int i=0;i<skinbmps->getNumItems();i++) + skinbmps->enumItem(i)->Release(); + + delete skinbmps; + } + if (envelope) + envelope->Release(); +} + +BltCanvas::BltCanvas(HBITMAP bmp) +{ + prevbmp = NULL; + bits = NULL; + fcoord = TRUE; + ourbmp = FALSE; + skinbmps = NULL; + envelope = NULL; + + hbmp = bmp; + ASSERT(hbmp != NULL); + + // create tha DC + hdc = CreateCompatibleDC(NULL); + prevbmp = (HBITMAP)SelectObject(hdc, hbmp); +} + +BltCanvas::BltCanvas() +{ + hbmp = NULL; + prevbmp = NULL; + bits = NULL; + fcoord = TRUE; + ourbmp = FALSE; + bpp = 32; // TODO: benski> pass as parameter? + skinbmps = NULL; + envelope = NULL; + hdc = CreateCompatibleDC(NULL); +} + +BltCanvas::BltCanvas(int w, int h, HWND wnd, int nb_bpp/*, unsigned char *pal, int palsize*/) +{ + hbmp = NULL; + prevbmp = NULL; + bits = NULL; + fcoord = TRUE; + ourbmp = FALSE; + bpp = nb_bpp; + skinbmps = NULL; + envelope = NULL; + hdc = CreateCompatibleDC(NULL); + AllocBitmap(w,h,nb_bpp); + + if (hbmp) + { + // create tha DC + + if (!hdc) { +// int x = GetLastError(); + } + prevbmp = (HBITMAP)SelectObject(hdc, hbmp); + } +} + +void BltCanvas::AllocBitmap(int w, int h, int nb_bpp) +{ + ASSERT(!hbmp); + ASSERT(w != 0 && h != 0); + if (w == 0) w = 1; + if (h == 0) h = 1; + + BITMAPINFO bmi; + MEMZERO(&bmi, sizeof(BITMAPINFO)); + //bmi.bmiHeader.biClrUsed = 0; // we memzero above, no need + //bmi.bmiHeader.biClrImportant = 0; // we memzero above, no need + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = ABS(w); + bmi.bmiHeader.biHeight = -ABS(h); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = nb_bpp; + bmi.bmiHeader.biCompression = BI_RGB; + //bmi.bmiHeader.biSizeImage = 0; // we memzero above, no need + //bmi.bmiHeader.biXPelsPerMeter = 0; // we memzero above, no need + //bmi.bmiHeader.biYPelsPerMeter = 0; // we memzero above, no need + //GdiFlush(); + hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); + + if (hbmp == NULL) + { + return ; + } + + ourbmp=TRUE; + GetObject(hbmp, sizeof(BITMAP), &bm); + width = bm.bmWidth; + height = ABS(bm.bmHeight); + pitch = bm.bmWidthBytes; +} + +void *BltCanvas::getBits() +{ + return bits; +} + +HBITMAP BltCanvas::getBitmap() +{ + return hbmp; +} + +SkinBitmap *BltCanvas::getSkinBitmap() +{ + // make a SkinBitmap envelope + if (!envelope) + envelope = new SkinBitmap(getBitmap(), getHDC(), 1, getBits()); + + // do not delete envelope, it's deleted in destructor + return envelope; +} + +SkinBitmap *BltCanvas::makeSkinBitmap() +{ + // make a clone of the bitmap - JF> what was that crap about envelopes? + SkinBitmap *clone = new SkinBitmap(getBitmap(), getHDC(), 1); + + if (!skinbmps) + skinbmps = new PtrList<SkinBitmap>; + skinbmps->addItem(clone); + + return clone; +} + +void BltCanvas::disposeSkinBitmap(SkinBitmap *b) +{ + if (skinbmps->haveItem(b)) + { + skinbmps->removeItem(b); + b->Release(); + } + else + { + DebugString("disposeSkinBitmap called on unknown pointer, you should call it from the object used to makeSkinBitmap()\n"); + } +} + +void BltCanvas::fillBits(COLORREF color) +{ + if (bpp == 32) + { // clear out the bits + DWORD *dwbits = (DWORD *)bits; + MEMFILL<DWORD>(dwbits, color, bm.bmWidth * bm.bmHeight); + } +} + +void BltCanvas::vflip(int vert_cells) +{ + ASSERT(bits != NULL); + // BITMAP bm; + // int r = GetObject(hbmp, sizeof(BITMAP), &bm); + // if (r == 0) return; + int w = bm.bmWidth, h = bm.bmHeight; + int bytes = 4 * w; + __int8 *tmpbuf = (__int8 *)MALLOC(bytes); + if (tmpbuf) + { + int cell_h = h / vert_cells; + for (int j = 0; j < vert_cells; j++) + for (int i = 0; i < cell_h / 2; i++) + { + char *p1, *p2; + p1 = (__int8 *)bits + bytes * i + (j * cell_h * bytes); + p2 = (__int8 *)bits + bytes * ((cell_h - 1) - i) + (j * cell_h * bytes); + if (p1 == p2) continue; + MEMCPY(tmpbuf, p1, bytes); + MEMCPY(p1, p2, bytes); + MEMCPY(p2, tmpbuf, bytes); + } + FREE(tmpbuf); + } +} + +void BltCanvas::hflip(int hor_cells) +{ + ASSERT(bits != NULL); + // todo: optimize + int w = bm.bmWidth, h = bm.bmHeight; + for (int i = 0;i < hor_cells;i++) + for (int x = 0;x < w / 2 / hor_cells;x++) + for (int y = 0;y < h;y++) + { + int *p = ((int *)bits) + x + y * w + (i * w / hor_cells); + int *d = ((int *)bits) + ((w / hor_cells) - x) + y * w + (i * w / hor_cells) - 1; + int t = *p; + *p = *d; + *d = t; + } +} + +void BltCanvas::maskColor(COLORREF from, COLORREF to) +{ + int n = bm.bmWidth * bm.bmHeight; + //GdiFlush(); + DWORD *b = (DWORD *)getBits(); + from &= 0xffffff; + while (n--) + { + if ((*b & 0xffffff) == from) + { + *b = to; + } + else *b |= 0xff000000; // force all other pixels non masked + b++; + } +} + +void BltCanvas::makeAlpha(int newalpha) +{ + int w, h; + getDim(&w, &h, NULL); + premultiply((ARGB32 *)getBits(), w*h, newalpha); +} + +#if 0 +void BltCanvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha) +{ + if (newalpha == -1) + { + for (; nwords > 0; nwords--, m_pBits++) + { + unsigned char *pixel = (unsigned char *)m_pBits; + unsigned int alpha = pixel[3]; + if (alpha == 255) continue; + pixel[0] = (pixel[0] * alpha) >> 8; // blue + pixel[1] = (pixel[1] * alpha) >> 8; // green + pixel[2] = (pixel[2] * alpha) >> 8; // red + } + } + else + { + for (; nwords > 0; nwords--, m_pBits++) + { + unsigned char *pixel = (unsigned char *)m_pBits; + pixel[0] = (pixel[0] * newalpha) >> 8; // blue + pixel[1] = (pixel[1] * newalpha) >> 8; // green + pixel[2] = (pixel[2] * newalpha) >> 8; // red + pixel[3] = (pixel[3] * newalpha) >> 8; // alpha + } + } +} +#endif + +// benski> this may not be completely safe. it's meant for skinbitmap::blittorect +// it doesn't take into account skin bitmaps, enveloped bitmaps, or any other things like that +void BltCanvas::DestructiveResize(int w, int h, int nb_bpp) +{ + if (hdc != NULL) + { + SelectObject(hdc, prevbmp); + prevbmp=0; + } + + if (ourbmp && hbmp) + { + DeleteObject(hbmp); + hbmp=NULL; + ourbmp=FALSE; + } + + // create tha DC + if (hdc == NULL) + hdc = CreateCompatibleDC(NULL); + + AllocBitmap(w,h,nb_bpp); + + prevbmp = (HBITMAP)SelectObject(hdc, hbmp); + if (envelope) envelope->Release(); + envelope=0; +} diff --git a/Src/tataki/canvas/win/bltcanvas.h b/Src/tataki/canvas/win/bltcanvas.h new file mode 100644 index 00000000..250e8ba3 --- /dev/null +++ b/Src/tataki/canvas/win/bltcanvas.h @@ -0,0 +1,41 @@ +#ifndef _BLTCANVAS_H +#define _BLTCANVAS_H + +#include "canvas.h" +#include <tataki/export.h> +#include <bfc/ptrlist.h> +class TATAKIAPI BltCanvas : public Canvas +{ +public: + BltCanvas(); + BltCanvas(int w, int h, HWND wnd=NULL, int nb_bpp=32/*, unsigned __int8 *pal=NULL,int palsize=0*/); + BltCanvas(HBITMAP bmp); + virtual ~BltCanvas(); + void *getBits(); + HBITMAP getBitmap(); + SkinBitmap *makeSkinBitmap(); // this one makes a new, with own bits + SkinBitmap *getSkinBitmap(); // this one gives a skinbitmap envoloppe of this bltcanvas + void disposeSkinBitmap(SkinBitmap *b); // call only after makeSkinBitmap + + void fillBits(COLORREF color); + + void vflip(int vert_cells=1); + void hflip(int hor_cells=1); + void maskColor(COLORREF from, COLORREF to); + void makeAlpha(int newalpha=-1); // -1 = premultiply using current alpha + + void DestructiveResize(int w, int h, int nb_bpp = 32); // resizes the bitmap, destroying the contents +private: // NONPORTABLE + + void AllocBitmap(int w, int h, int nb_bpp); + HBITMAP hbmp, prevbmp; + PtrList<SkinBitmap> *skinbmps; + SkinBitmap *envelope; + BITMAP bm; + bool ourbmp; + int bpp; + + //void premultiply(ARGB32 *m_pBits, int nwords, int newalpha=-1); +}; + +#endif diff --git a/Src/tataki/canvas/win/canvas.h b/Src/tataki/canvas/win/canvas.h new file mode 100644 index 00000000..179e3498 --- /dev/null +++ b/Src/tataki/canvas/win/canvas.h @@ -0,0 +1,368 @@ +//NONPORTABLE: the interface is portable, but the implementation sure isn't +#ifndef _CANVAS_H +#define _CANVAS_H + +#if defined _WIN64 || defined _WIN32 +#include <ddraw.h> +#endif + +//#include <bfc/common.h> +#include <tataki/export.h> + +class Canvas; +class MemCanvasBmp; +class BaseWnd; +class ifc_window; +class api_region; +class SkinBitmap; + +#include <bfc/stack.h> +#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later +#include <bfc/dispatch.h> + +enum { +#ifdef WIN32 + PENSTYLE_SOLID = PS_SOLID, + PENSTYLE_DASH = PS_DASH, + PENSTYLE_DOT = PS_DOT, +#else + PENSTYLE_SOLID = LineSolid, + PENSTYLE_DASH = LineDoubleDash, + PENSTYLE_DOT = LineDoubleDash, +#endif +}; + +#include <tataki/canvas/ifc_canvas.h> +class ifc_canvas; +class RegionI; +typedef struct +{ + int style; + int width; + COLORREF color; + HPEN hpen; +} +penstruct; + +class TATAKIAPI NOVTABLE Canvas : public ifc_canvas +{ +protected: + Canvas(); +public: + virtual ~Canvas(); + +// ifc_canvas stuff + HDC getHDC(); + ifc_window *getRootWnd(); + void *getBits(); + void getOffsets(int *x, int *y); + bool isFixedCoords(); + bool getDim(int *w, int *h, int *p); + void setBaseWnd(BaseWnd *b); +// end ifc_canvas stuff + + virtual BaseWnd *getBaseWnd(); + + // graphics commands + void fillRect(const RECT *r, COLORREF color); + void fillRectAlpha(const RECT *r, COLORREF color, int alpha); + void fillRgn(RegionI *r, COLORREF color); + void drawRect(const RECT *r, int solid, COLORREF color, int alpha = 255); + + // text commands + const wchar_t *getTextFont(); + int getTextSize(); + int getTextBold(); + int getTextAntialias(); + int getTextOpaque(); + int getTextUnderline(); + int getTextItalic(); + int getTextAlign(); + COLORREF getTextColor(); + COLORREF getTextBkColor(); + + void pushPen(COLORREF color); + void pushPen(int style, int width, COLORREF color); + void popPen(); + + int getPenStyle(); + COLORREF getPenColor(); + int getPenWidth(); + + // normal text + void textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + // returns height used + void textOutWrapped(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOutWrappedPathed(int x, int y, int w, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + void textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo); + + int getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo); + int getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo); + void getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo); + int getTextHeight(const Wasabi::FontInfo *fontInfo) + { + return getTextHeight(L"M", fontInfo); + } + + void selectClipRgn(api_region *r); + int getClipBox(RECT *r); // returns 0 if no clipping region + int getClipRgn(api_region *r); // returns 0 if no clipping region + + // Deprecated? + void moveTo(int x, int y); + void lineTo(int x, int y); + + void lineDraw(int fromX, int fromY, int toX, int toY); + + void drawSysObject(const RECT *r, int sysobj, int alpha = 255); + + void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha = 255); + void blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255); + void stretch(ifc_canvas *canvas, int x, int y, int w, int h); + // src* are in 16.16 fixed point + void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth); + void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255); + void antiAliasTo(Canvas *dest, int w, int h, int aafactor); + + int getXOffset() const + { + return xoffset; + } + int getYOffset() const + { + return yoffset; + } + void offsetRect(RECT *r); + void debug(); + + void colorToColor(COLORREF from, COLORREF to, RECT *r); + double getSystemFontScale(); + static void premultiply(ARGB32 *m_pBits, int nwords, int newalpha = -1); + +protected: + const Wasabi::FontInfo *getFontInfo() + { + if (userFontInfo) + return userFontInfo; + else + return &canvasFontInfo; + } + + RECVS_DISPATCH; + + HDC hdc; + void *bits; + int width, height, pitch; + bool fcoord; + int xoffset, yoffset; + BaseWnd *srcwnd; + Wasabi::FontInfo canvasFontInfo; // to hold our defaults + const Wasabi::FontInfo *userFontInfo; // passed from someone calling this function. usually is NULL + +private: + Stack<penstruct> penstack; + + int penstyle; + COLORREF pencolor; + int penwidth; + +#ifdef WIN32 + HPEN defpen; + HPEN curpen; +#endif +#ifdef LINUX + int raster_x, raster_y; +#endif + +}; + +namespace DrawSysObj +{ +enum { + BUTTON, BUTTON_PUSHED, BUTTON_DISABLED, + OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED, + OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED, + OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED, + OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED, +}; +}; + +class TATAKIAPI WndCanvas : public Canvas +{ +public: + WndCanvas(); + WndCanvas(BaseWnd *basewnd); + virtual ~WndCanvas(); + + // address client area + int attachToClient(BaseWnd *basewnd); +//CUT // address entire window +//CUT int attachToWnd(HWND _hWnd); // NONPORTABLE: avoid! mostly for mainwnd + +private: + HWND hWnd; +}; + +class TATAKIAPI PaintCanvas : public Canvas +{ +public: + PaintCanvas(); + virtual ~PaintCanvas(); + + int beginPaint(BaseWnd *basewnd); + int beginPaint(HWND wnd); + void getRcPaint(RECT *r); + +private: // NONPORTABLE + HWND hWnd; + PAINTSTRUCT ps; +}; + +class BltCanvas; +class TATAKIAPI PaintBltCanvas : public Canvas +{ +public: + PaintBltCanvas(); + virtual ~PaintBltCanvas(); + int beginPaint(BaseWnd *basewnd); + int beginPaintNC(BaseWnd *basewnd); + + void *getBits(); + void getRcPaint(RECT *r); + +private: // NONPORTABLE + HWND hWnd; + PAINTSTRUCT ps; + HDC wnddc; + HBITMAP hbmp, prevbmp; + bool nonclient; +#ifdef LINUX + BltCanvas *blitter; +#endif +}; + +class TATAKIAPI MemCanvas : public Canvas +{ +public: + MemCanvas(); + virtual ~MemCanvas(); + + int createCompatible(Canvas *canvas); +private: +}; + +class TATAKIAPI DCCanvas : public Canvas +{ +public: + DCCanvas(HDC clone = NULL, BaseWnd *srcWnd = NULL); + virtual ~DCCanvas(); + + int cloneDC(HDC clone, BaseWnd *srcWnd = NULL); +}; + +class TATAKIAPI SysCanvas : public Canvas +{ +public: + SysCanvas(); + virtual ~SysCanvas(); +}; + +/* benski> + a quick Canvas class to be created on-the-fly when you need to retrieve information about fonts + e.g. getTextExtent + don't try to draw with it or bad things will happen. + +*/ +class TATAKIAPI TextInfoCanvas : public Canvas +{ +public: + TextInfoCanvas(BaseWnd *basewnd); + virtual ~TextInfoCanvas(); +private: + HWND hWnd; +}; + +class TATAKIAPI DCBltCanvas : public Canvas +{ +public: + DCBltCanvas(); + virtual ~DCBltCanvas(); + + int cloneDC(HDC clone, RECT *r, BaseWnd *srcWnd = NULL); + int setOrigDC(HDC neworigdc); // set to null to prevent commitdc on delete, non null to change destination dc + int commitDC(void); // allows commit to DC without deleting +#if 0 + int cloneCanvas(ifc_canvas *clone, RECT *r); +#endif + +protected: + HDC origdc; + RECT rect; + HBITMAP hbmp, prevbmp; +}; + +class TATAKIAPI DCExBltCanvas : public DCBltCanvas +{ +public: + DCExBltCanvas(HWND hWnd, HRGN hrgnClip, DWORD flags); + + ~DCExBltCanvas(); +private: + HWND hwnd; +}; + + +// note: getBaseWnd() returns NULL for this class +class TATAKIAPI BaseCloneCanvas : public Canvas +{ +public: + BaseCloneCanvas(ifc_canvas *cloner = NULL); + virtual ~BaseCloneCanvas(); + + int clone(ifc_canvas *cloner); +}; + + + +#ifdef WIN32 +class TATAKIAPI DDSurfaceCanvas : public Canvas +{ + +public: + + DDSurfaceCanvas(LPDIRECTDRAWSURFACE surface, int w, int h); + virtual ~DDSurfaceCanvas(); + + int isready(); + void enter(); + void exit(); + +private: + LPDIRECTDRAWSURFACE surf; + int _w, _h; +}; +#endif + +class TATAKIAPI BitsCanvas : public Canvas +{ +public: + BitsCanvas(void *_bits, int _w, int _h) + { + bits=_bits; + width=_w; + height=_h; + pitch=_w; + } +}; + +enum +{ + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT +}; + +#endif diff --git a/Src/tataki/canvas/win/win32_canvas.cpp b/Src/tataki/canvas/win/win32_canvas.cpp new file mode 100644 index 00000000..c3d2ad8b --- /dev/null +++ b/Src/tataki/canvas/win/win32_canvas.cpp @@ -0,0 +1,1489 @@ +#ifndef _WIN32 +#error this file is for windows only. Don't include it in your project/makefile for other platforms +#else +#include <tataki/export.h> +#include <tataki/api__tataki.h> +#include <tataki/blending/blending.h> +#include "canvas.h" +#include <tataki/bitmap/bitmap.h> +#include <tataki/region/region.h> +#include <api/wnd/basewnd.h> +#include <api/wnd/fontdef.h> +#include <api/wnd/paintsets.h> + +#include <bfc/assert.h> + +#include "bltcanvas.h" +#include <nsutil/alpha.h> +#include <nsutil/image.h> + +#define CBCLASS Canvas +START_DISPATCH; +CB(GETHDC, getHDC); +CB(GETROOTWND, getRootWnd); +CB(GETBITS, getBits); +VCB(GETOFFSETS, getOffsets); +CB(ISFIXEDCOORDS, isFixedCoords); +CB(GETDIM, getDim); +CB(GETTEXTFONT, getTextFont); +CB(GETTEXTSIZE, getTextSize); +CB(GETTEXTBOLD, getTextBold); +CB(GETTEXTOPAQUE, getTextOpaque); +CB(GETTEXTUNDERLINE, getTextUnderline); +CB(GETTEXTITALIC, getTextItalic); +CB(GETTEXTALIGN, getTextAlign); +CB(GETTEXTCOLOR, getTextColor); +CB(GETTEXTBKCOLOR, getTextBkColor); +CB(GETTEXTAA, getTextAntialias); +CB(GETCLIPBOX, getClipBox); +END_DISPATCH; +#undef CBCLASS + +//NONPORTABLE + +extern const wchar_t wasabi_default_fontnameW[]; + +Canvas::Canvas() + : hdc(NULL), + bits(NULL), + srcwnd(NULL), + fcoord(FALSE), + xoffset(0), yoffset(0), + width(0), + height(0), + pitch(0), + defpen(NULL), + curpen(NULL), + userFontInfo(0) +{ + + //tfont = new String; // using dynamic tfont here coz we need to manage em with stack, so stacking fonts won't take sizeof(String) and their destruction will not fuxor everything + //tfont->setValue(wasabi_default_fontname); +} + +Canvas::~Canvas() +{ + if (getHDC() && defpen != NULL) + { + SelectObject(getHDC(), defpen); + DeleteObject(curpen); + } + + if (!penstack.isempty()) + DebugStringW(L"Pen stack not empty in Canvas::~Canvas !"); +} + +void Canvas::setBaseWnd(BaseWnd *b) +{ + srcwnd = b; +} + +HDC Canvas::getHDC() +{ + return hdc; +} + +ifc_window *Canvas::getRootWnd() +{ + return srcwnd; +} + +void *Canvas::getBits() +{ + return bits; +} + +bool Canvas::getDim(int *w, int *h, int *p) +{ + if (w) *w = width; + if (h) *h = height; + if (p) *p = pitch; + return FALSE; +} + +void Canvas::getOffsets(int *x, int *y) +{ + if (x != NULL) *x = getXOffset(); + if (y != NULL) *y = getYOffset(); +} + +bool Canvas::isFixedCoords() +{ + return fcoord; +} + +BaseWnd *Canvas::getBaseWnd() +{ + return srcwnd; +} + +void Canvas::fillRgn(RegionI *r, COLORREF color) +{ + ASSERT(r != NULL); + HBRUSH brush = CreateSolidBrush(color); + FillRgn(hdc, r->getOSHandle(), brush); + DeleteObject(brush); +} + +void Canvas::fillRect(const RECT *r, COLORREF color) +{ + ASSERT(r != NULL); +#if 0 + HBRUSH brush; + if (color == RGB(0, 0, 0)) + { + FillRect(hdc, r, (HBRUSH)GetStockObject(BLACK_BRUSH)); + return ; + } + RECT rr = *r; + offsetRect(&rr); + + brush = CreateSolidBrush(color); + FillRect(hdc, &rr, brush); + DeleteObject(brush); +#else +// see: http://ooeygui.typepad.com/ooey_gui/2005/06/tip_fast_solid_.html +COLORREF clrOld = SetBkColor(hdc, color); +RECT rr = *r; +offsetRect(&rr); +ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rr, NULL, 0, NULL); +SetBkColor(hdc, clrOld); +#endif +} + +void Canvas::fillRectAlpha(const RECT *r, COLORREF color, int alpha) +{ + RECT blitr; + RECT clipr; + getClipBox(&clipr); + IntersectRect(&blitr, &clipr, r); + uint8_t *bits8 = (uint8_t *)(bits) + blitr.left*4 + blitr.top * pitch; + nsutil_image_FillRectAlpha_RGB32((RGB32 *)(bits8), pitch, blitr.right-blitr.left, blitr.bottom-blitr.top, color, alpha); +} + +void Canvas::drawRect(const RECT *r, int solid, COLORREF color, int alpha) +{ +#if 0 + unsigned int blah = (unsigned int)alpha; + color = RGBTOBGR(color); + color = (color & 0xFFFFFF) | (blah << 24); + BltCanvas::premultiply(&color, 1); + int ox, oy; + getOffsets(&ox, &oy); + int w, h, pitch; + getDim(&w, &h, &pitch); + RECT _r = *r; + _r.right = MIN<int>(r->right, w); + _r.bottom = MIN<int>(r->bottom, h); + int _l = r->bottom - r->top; + int m = _r.bottom - _r.top; + int l = _l; + pitch /= 4; + int *p = (int *)bits + ox + r->left + (oy + r->top) * pitch; + int n = r->right - r->left; + int maxn = _r.right - _r.left; + while (l-- && m--) + { + int _n = maxn; + if (l == _l - 1 || !l) + { + if (solid) + { + while (_n--) + { + *p = Blenders::BLEND_ADJ2(*p, color); + p++; + } + } + else + { + while (_n--) + { + if (_n % 2) *p = Blenders::BLEND_ADJ2(*p, color); + p++; + } + } + p += n - maxn; + } + else + { + if (solid || l % 2) + *p = Blenders::BLEND_ADJ2(*p, color); + p += n - 1; + if (n == maxn && (solid || l % 2)) + *p = Blenders::BLEND_ADJ2(*p, color); + p++; + } + p += pitch - n; + } +#else +HBRUSH oldbrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); +HPEN oldpen, pen; +pen = CreatePen(solid ? PS_SOLID : PS_DOT, 0, color); +oldpen = (HPEN)SelectObject(hdc, pen); +ASSERT(r != NULL); +RECT rr = *r; +offsetRect(&rr); +Rectangle(hdc, rr.left, rr.top, rr.right, rr.bottom); +SelectObject(hdc, oldpen); +SelectObject(hdc, oldbrush); +DeleteObject(pen); +#endif +} + +int Canvas::getTextAlign() +{ + return getFontInfo()->alignFlags; +} + +int Canvas::getTextOpaque() +{ + return getFontInfo()->opaque; +} + + +int Canvas::getTextUnderline() +{ + return getFontInfo()->underline; +} + +int Canvas::getTextItalic() +{ + return getFontInfo()->italic; +} + +int Canvas::getTextBold() +{ + return getFontInfo()->bold; +} + +int Canvas::getTextAntialias() +{ + return getFontInfo()->antialias; +} + +void Canvas::pushPen(COLORREF color) +{ + pushPen(PENSTYLE_SOLID, 1, color); +} + +void Canvas::pushPen(int style, int width, COLORREF color) +{ + ASSERT(getHDC() != NULL); + penstyle = style; + penwidth = width; + pencolor = color; + penstruct s; + curpen = CreatePen(style, width, color); + HPEN oldpen = (HPEN)SelectObject(getHDC(), curpen); + s.style = style; + s.width = width; + s.color = color; + s.hpen = oldpen; + penstack.push(s); +} + +void Canvas::popPen() +{ + ASSERT(getHDC() != NULL); + if (penstack.isempty()) return ; + penstruct s; + penstack.pop(&s); + SelectObject(getHDC(), s.hpen); + DeleteObject(curpen); +} + +int Canvas::getPenStyle() +{ + return penstyle; +} + +COLORREF Canvas::getPenColor() +{ + return pencolor; +} + +int Canvas::getPenWidth() +{ + return penwidth; +} + +COLORREF Canvas::getTextColor() +{ + return getFontInfo()->color; +} + +COLORREF Canvas::getTextBkColor() +{ + return getFontInfo()->bgColor; +} + +int Canvas::getTextSize() +{ + return getFontInfo()->pointSize; +} + +const wchar_t *Canvas::getTextFont() +{ + return getFontInfo()->face; +} + +void Canvas::moveTo(int x, int y) +{ + MoveToEx(hdc, x, y, NULL); +} + +void Canvas::lineTo(int x, int y) +{ + LineTo(hdc, x, y); +} + +void Canvas::lineDraw(int fromX, int fromY, int toX, int toY) +{ + MoveToEx(hdc, fromX, fromY, NULL); + LineTo(hdc, toX, toY); +} + +void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha) +{ +#ifndef _NOSTUDIO + RECT i_dont_trust_ms_with_my_rect = *r; + switch (sysobj) + { + case DrawSysObj::BUTTON: + WASABI_API_WND->paintset_render(Paintset::BUTTONUP, this, r, alpha); + break; + case DrawSysObj::BUTTON_PUSHED: + WASABI_API_WND->paintset_render(Paintset::BUTTONDOWN, this, r, alpha); + break; + case DrawSysObj::BUTTON_DISABLED: + WASABI_API_WND->paintset_render(Paintset::BUTTONDISABLED, this, r, alpha); + break; +#ifdef WIN32 + case DrawSysObj::OSBUTTON: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH); + } + break; + case DrawSysObj::OSBUTTON_PUSHED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED); + } + break; + case DrawSysObj::OSBUTTON_DISABLED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_INACTIVE); + } + break; + + case DrawSysObj::OSBUTTON_CLOSE: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE); + } + break; + case DrawSysObj::OSBUTTON_CLOSE_PUSHED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_PUSHED); + } + break; + case DrawSysObj::OSBUTTON_CLOSE_DISABLED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_INACTIVE); + } + break; + + case DrawSysObj::OSBUTTON_MINIMIZE: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN); + } + break; + case DrawSysObj::OSBUTTON_MINIMIZE_PUSHED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_PUSHED); + } + break; + case DrawSysObj::OSBUTTON_MINIMIZE_DISABLED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_INACTIVE); + } + break; + + case DrawSysObj::OSBUTTON_MAXIMIZE: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX); + } + break; + case DrawSysObj::OSBUTTON_MAXIMIZE_PUSHED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_PUSHED); + } + break; + case DrawSysObj::OSBUTTON_MAXIMIZE_DISABLED: + { + DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_INACTIVE); + } + break; +#else +#error port me! +#endif + break; + } +#endif +} + +void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_NORMAL, x, y, 0, 0, txt); + userFontInfo = 0; +} + +void Canvas::textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_RECT, x, y, w, h, txt); + userFontInfo = 0; +} + +void Canvas::textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_ELLIPSED, x, y, w, h, txt); + userFontInfo = 0; +} + +void Canvas::textOutWrapped(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPED, x, y, w, h, (txt)); + userFontInfo = 0; +} + +void Canvas::textOutWrappedPathed(int x, int y, int w, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPEDPATHED, x, y, w, 0, (txt)); + userFontInfo = 0; +} + +void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_CENTERED, r->left, r->top, r->right, r->bottom, (txt)); + userFontInfo = 0; +} + +int Canvas::getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTH, (text), NULL, NULL); + userFontInfo = 0; + return ret; +} + +int Canvas::getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_HEIGHT, (text), NULL, NULL); + userFontInfo = 0; + return ret; +} + +void Canvas::getTextExtent(const wchar_t *txt, int *w, int *h, const Wasabi::FontInfo *fontInfo) +{ + userFontInfo = fontInfo; + WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTHHEIGHT, (txt), w, h); + userFontInfo = 0; +} + +void Canvas::offsetRect(RECT *r) +{ + ASSERT(r != NULL); + r->left += xoffset; + r->right += xoffset; + r->top += yoffset; + r->bottom += yoffset; +} + +void Canvas::selectClipRgn(api_region *r) +{ + SelectClipRgn(hdc, r ? r->getOSHandle() : NULL); +} + +int Canvas::getClipBox(RECT *r) +{ + RECT dummy; + if (!r) r = &dummy; + return GetClipBox(hdc, r); +} + +int Canvas::getClipRgn(api_region *r) +{ + ASSERT(r != NULL); + return GetClipRgn(hdc, r->getOSHandle()); +} + +//FG> added blit canvas to canvas +void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + char *srcbits = (char *)getBits(); + char *destbits = (char *)dest->getBits(); + RECT clipr; + if (srcbits && destbits && GetClipBox(dest->getHDC(), &clipr) == SIMPLEREGION) + { + int srcimg_w, srcimg_h, srcimg_p; + getDim(&srcimg_w, &srcimg_h, &srcimg_p); + int dstimg_w, dstimg_h, dstimg_p; + dest->getDim(&dstimg_w, &dstimg_h, &dstimg_p); + + if (srcx < 0) + { + dstx -= srcx; dstw += srcx; srcx = 0; + } + if (srcy < 0) + { + dsty -= srcy; dsth += srcy; srcy = 0; + } + if (srcx + dstw >= srcimg_w) dstw = srcimg_w - srcx; + if (srcy + dsth >= srcimg_h) dsth = srcimg_h - srcy; + + if (dstx < clipr.left) + { + srcx += clipr.left - dstx; dstw -= clipr.left - dstx; dstx = clipr.left; + } + if (dsty < clipr.top) + { + srcy += clipr.top - dsty; dsth -= clipr.top - dsty; dsty = clipr.top; + } + + if (dstx + dstw >= clipr.right) dstw = clipr.right - dstx; + if (dsty + dsth >= clipr.bottom) dsth = clipr.bottom - dsty; + + if (!dstw || !dsth) return ; + + int y; + int yl = dsty + dsth; + for (y = dsty; y < yl; y++) + { + MEMCPY32(destbits + y*dstimg_p + dstx*4, srcbits + srcy*srcimg_p + srcx*4, dstw); + srcy++; + } + } + else + { + //GdiFlush(); + BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx, srcy, SRCCOPY); + } +} + +#pragma comment(lib, "msimg32.lib") + +void Canvas::stretch(ifc_canvas *canvas, int x, int y, int w, int h) +{ + if (bits) + { + SkinBitmap temp((ARGB32 *)bits, width, height); + temp.stretch(canvas, x,y,w,h); + } + else + { + BLENDFUNCTION blendFn; + blendFn.BlendOp = AC_SRC_OVER; + blendFn.BlendFlags = 0; + blendFn.SourceConstantAlpha = 255; + blendFn.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(canvas->getHDC(), + x, y, + w, h, + getHDC(), + 0, 0, + width, height, + blendFn); + } +} + +void Canvas::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha) +{ + if (bits) + { + SkinBitmap temp((ARGB32 *)bits, width, height); + temp.blitAlpha(canvas, x,y,alpha); + } + else + { + BLENDFUNCTION blendFn; + blendFn.BlendOp = AC_SRC_OVER; + blendFn.BlendFlags = 0; + blendFn.SourceConstantAlpha = alpha; + blendFn.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(canvas->getHDC(), + x, y, + width, height, + getHDC(), + 0, 0, + width, height, + blendFn); + } +} + +void Canvas::stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) +{ + if (bits) + { + SkinBitmap temp((ARGB32 *)bits, width, height); + temp.stretchToRectAlpha(canvas, src, dst, alpha); + } + else + { + BLENDFUNCTION blendFn; + blendFn.BlendOp = AC_SRC_OVER; + blendFn.BlendFlags = 0; + blendFn.SourceConstantAlpha = alpha; + blendFn.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(canvas->getHDC(), + dst->left, dst->top, + dst->right - dst->left, dst->bottom - dst->top, + getHDC(), + src->left, src->top, + src->right - src->left, src->bottom - src->top, + blendFn); + } +} + +void Canvas::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) +{ + if (bits) + { + SkinBitmap temp((ARGB32 *)bits, width, height); + temp.blitToRect(canvas, src, dst, alpha); + } + else + { + BLENDFUNCTION blendFn; + blendFn.BlendOp = AC_SRC_OVER; + blendFn.BlendFlags = 0; + blendFn.SourceConstantAlpha = alpha; + blendFn.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(canvas->getHDC(), + dst->left, dst->top, + dst->right - dst->left, dst->bottom - dst->top, + getHDC(), + src->left, src->top, + src->right - src->left, src->bottom - src->top, + blendFn); + } +} + +// src* are in fixed point +static void scale_internal(int srcx, int srcy, int srcw, int srch, void *srcdib, int srcdib_w, int srcdib_h, int srcdib_p, int dstx, int dsty, int dstw, int dsth, void *dstdib, int nofilter) +{ + // scaling up + if ((dstw << 16) >= srcw && (dsth << 16) >= srch) + { + int y; + int SY, dX, dY; + int Xend = (srcdib_w - 2) << 16; + SY = srcy; + dX = srcw / dstw; + dY = srch / dsth; + + int xstart = 0; + int xp = srcx >> 16; + if (xp < 0) + { + xstart = -xp; + srcx += xstart * dX; + } + + int xend = dstw; + xp = (srcx + (dX * (xend - xstart))) >> 16; + if (xp > srcdib_w) + { + xend = xstart + srcdib_w - (srcx >> 16); + } + + for (y = 0; y < dsth; y ++) + { + int yp = (SY >> 16); + if (yp >= 0) + { + int x; + int SX = srcx; + unsigned int *out = (unsigned int*)dstdib + xstart + y * dstw; + int end = yp >= srcdib_h - 1; + if (nofilter || end) + { + if (end) yp = srcdib_h - 1; + unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p); + for (x = xstart; x < xend; x ++) // quick hack to draw last line + { + *out++ = in[SX >> 16]; + SX += dX; + } + if (end) break; + } + else + { + unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p); + +#ifndef NO_MMX + if (Blenders::MMX_AVAILABLE()) + { + for (x = xstart; x < xend; x ++) + { + if (SX > Xend) *out++ = Blenders::BLEND4_MMX(in + (Xend >> 16), srcdib_w, 0xffff, SY); + else *out++ = Blenders::BLEND4_MMX(in + (SX >> 16), srcdib_w, SX, SY); + SX += dX; + } + } + else +#endif + + { + for (x = xstart; x < xend; x ++) + { + if (SX > Xend) *out++ = Blenders::BLEND4(in + (Xend >> 16), srcdib_w, 0xffff, SY); + else *out++ = Blenders::BLEND4(in + (SX >> 16), srcdib_w, SX, SY); + SX += dX; + } + } + } + } + SY += dY; + } + // end of scaling up + } + else // we are scaling down -- THIS IS SLOW AND MAY BREAK THINGS. :) + { + int y; + int SY, dX, dY; + SY = srcy; + dX = srcw / dstw; + dY = srch / dsth; + + int xstart = 0; + int xp = srcx >> 16; + if (xp < 0) + { + xstart = -xp; + srcx += xstart * dX; + } + + int xend = dstw; + xp = (srcx + (dX * (xend - xstart))) >> 16; + if (xp > srcdib_w) + { + xend = xstart + srcdib_w - (srcx >> 16); + } + + for (y = 0; y < dsth; y ++) + { + // start and end of y source block + int vStart = SY; + int vEnd = SY + dY; + + int x; + int SX = srcx; + unsigned char *out = (unsigned char *)((unsigned int*)dstdib + xstart + y * dstw); + for (x = xstart; x < xend; x ++) + { + if (((char *)out+4) >= ((char *)dstdib + 4*dstw*dsth)) + break; + int uStart = SX; + int uEnd = SX + dX; + // calculate sum of rectangle. + + int cnt = 0; + __int64 accum[4] = {0, }; + int v, u; + for (v = vStart; v < vEnd; v += 65536) + { + unsigned int vscale = 65535; + + if (v == vStart) + { + vscale = 65535 - (v & 0xffff); + } + else if ((vEnd - v) < 65536) + { + vscale = (vEnd - v) & 0xffff; + } + + int vp = v >> 16; + unsigned char *in = (unsigned char*)((char *)srcdib + vp * srcdib_p + 4 * (uStart >> 16)); + for (u = uStart; u < uEnd; u += 65536) + { + if (((char *)in+4) >= ((char *)srcdib + srcdib_p*srcdib_h)) + break; + unsigned int uscale = vscale; + if (u == uStart) + { + uscale *= 65535 - (u & 0xffff); + uscale >>= 16; + } + else if ((uEnd - u) < 65536) + { + uscale *= (uEnd - u) & 0xffff; + uscale >>= 16; + } + cnt += uscale; + if (uscale == 65535) + { + accum[0] += (in[0] << 16) - in[0]; + accum[1] += (in[1] << 16) - in[1]; + accum[2] += (in[2] << 16) - in[2]; + accum[3] += (in[3] << 16) - in[3]; + } + else + { + accum[0] += in[0] * uscale; + accum[1] += in[1] * uscale; + accum[2] += in[2] * uscale; + accum[3] += in[3] * uscale; + } + in += 4; + } + } + if (!cnt) cnt++; + + out[0] = (uint8_t)(accum[0] / cnt); + out[1] = (uint8_t)(accum[1] / cnt); + out[2] = (uint8_t)(accum[2] / cnt); + out[3] = (uint8_t)(accum[3] / cnt); + out += 4; + + SX += dX; + } + SY += dY; + } + // end of scaling down + } + +#ifndef NO_MMX + Blenders::BLEND_MMX_END(); +#endif +} + + +// src* are in fixed point +void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth) +{ + //GdiFlush(); + int done = 0; + void *srcdib = getBits(); + + if (!dstw || !dsth || !srcw || !srch) return ; + if (srcdib) + { + int srcdib_w, srcdib_h, srcdib_p; + getDim(&srcdib_w, &srcdib_h, &srcdib_p); + + void *dstdib; + BITMAPINFO dstbmi = {0}; + HDC hMemDC; + HBITMAP hsrcdib; + dstbmi.bmiHeader.biSize = sizeof(dstbmi.bmiHeader); + dstbmi.bmiHeader.biWidth = dstw; + dstbmi.bmiHeader.biHeight = -ABS(dsth); + dstbmi.bmiHeader.biPlanes = 1; + dstbmi.bmiHeader.biBitCount = 32; + dstbmi.bmiHeader.biCompression = BI_RGB; + hMemDC = CreateCompatibleDC(NULL); + hsrcdib = CreateDIBSection(hMemDC, &dstbmi, DIB_RGB_COLORS, &dstdib, NULL, 0); + if (hsrcdib) + { + HBITMAP hprev = (HBITMAP)SelectObject(hMemDC, hsrcdib); + + scale_internal(srcx,srcy,srcw,srch,srcdib,srcdib_w,srcdib_h,srcdib_p,dstx,dsty,dstw,dsth,dstdib,0); + + BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, hMemDC, 0, 0, SRCCOPY); + done++; + + SelectObject(hMemDC, hprev); + DeleteObject(hsrcdib); + } + DeleteDC(hMemDC); + } + + if (!done) + { + SetStretchBltMode(dest->getHDC(), COLORONCOLOR); + StretchBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx >> 16, srcy >> 16, srcw >> 16, srch >> 16, SRCCOPY); + } +} + +#define DEBUG_SCREEN_SHIFT 0 +void Canvas::debug() +{ + SysCanvas c; + int w, h; + getDim(&w, &h, NULL); + blit(0, 0, &c, DEBUG_SCREEN_SHIFT, 0, w, h); +} + +#define BF2 (~((3<<24)|(3<<16)|(3<<8)|3)) + +void Canvas::antiAliasTo(Canvas *dest, int w, int h, int aafactor) +{ + ASSERT(aafactor != 0); + if (aafactor == 1) + { + blit(0, 0, dest, 0, 0, w, h); + return ; + } + ASSERT(getBits() != NULL); + ASSERT(dest->getBits() != NULL); + if (getBits() == NULL || dest->getBits() == NULL) return ; + ASSERTPR(aafactor <= 2, "too lazy to generalize the code right now :)"); + //GdiFlush(); + // we should really store the bpp too + int aaw = w * aafactor; + unsigned long *s1 = (unsigned long *)getBits(), *s2 = s1 + 1; + unsigned long *s3 = s1 + aaw, *s4 = s3 + 1; + unsigned long *d = (unsigned long *)dest->getBits(); +#if 1 + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++) + { + unsigned long tmp = ((*s1 & BF2) >> 2) + ((*s2 & BF2) >> 2) + ((*s3 & BF2) >> 2) + ((*s4 & BF2) >> 2); + *d++ = tmp; + + s1 += 2; s2 += 2; + s3 += 2; s4 += 2; + } + s1 += aaw; s2 += aaw; + s3 += aaw; s4 += aaw; + } +#else +for (int x = 0; x < w * h; x++) d[x] = s1[x]; +#endif +} + +void Canvas::colorToColor(COLORREF from, COLORREF to, RECT *r) +{ + int w, h, ox, oy; + + // convert to bitmap order + from = RGBTOBGR(from); + to = RGBTOBGR(to); + + COLORREF *p; + getDim(&w, &h, NULL); + p = (COLORREF *)getBits(); + getOffsets(&ox, &oy); + p += ox + r->left + (oy + r->top) * w; + int rw = r->right - r->left; + for (int j = r->top;j < r->bottom;j++) + { + for (int i = r->left;i < r->right;i++) + { + if (*p == from) + *p = to; + p++; + } + p += w - rw; + } +} + +double Canvas::getSystemFontScale() +{ + if (WASABI_API_CONFIG) + { + int v = WASABI_API_CONFIG->getIntPublic(L"manualsysmetrics", -1); + if (v != -1) return (v / 100.0f); + } + + int nLogDPIX = GetDeviceCaps(getHDC(), LOGPIXELSX); + return ((float)nLogDPIX / 96.0f); +} + +void Canvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha) +{ + if (newalpha == -1) + { + nsutil_alpha_Premultiply_RGB32(m_pBits, nwords, nwords, 1); + /* + for (; nwords > 0; nwords--, m_pBits++) + { + unsigned char *pixel = (unsigned char *)m_pBits; + unsigned int alpha = pixel[3]; + if (alpha == 255) continue; + pixel[0] = (pixel[0] * alpha) >> 8; // blue + pixel[1] = (pixel[1] * alpha) >> 8; // green + pixel[2] = (pixel[2] * alpha) >> 8; // red + } + */ + } + else + { + nsutil_alpha_PremultiplyValue_RGB8(m_pBits, nwords, nwords, 1, newalpha); + /* + for (; nwords > 0; nwords--, m_pBits++) + { + unsigned char *pixel = (unsigned char *)m_pBits; + pixel[0] = (pixel[0] * newalpha) >> 8; // blue + pixel[1] = (pixel[1] * newalpha) >> 8; // green + pixel[2] = (pixel[2] * newalpha) >> 8; // red + pixel[3] = (pixel[3] * newalpha) >> 8; // alpha + } + */ + } +} + +TextInfoCanvas::TextInfoCanvas(BaseWnd *basewnd) +{ + ASSERT(basewnd != NULL); + hWnd = basewnd->gethWnd(); + hdc = GetDC(hWnd); +} + +TextInfoCanvas::~TextInfoCanvas() +{ + if (hdc) + ReleaseDC(hWnd, hdc); +} + +WndCanvas::WndCanvas(BaseWnd *basewnd) +{ + attachToClient(basewnd); +} + +WndCanvas::WndCanvas() +{ + hWnd = NULL; +} + +WndCanvas::~WndCanvas() +{ + if (hWnd != NULL && hdc != NULL) ReleaseDC(hWnd, hdc); + hdc = NULL; +} + +int WndCanvas::attachToClient(BaseWnd *basewnd) +{ + if (basewnd == NULL) + return 0; + + hWnd = basewnd->gethWnd(); + if (hWnd == NULL) + return 0; + + hdc = GetDC(hWnd); + if (hdc == NULL) + return 0; + + srcwnd = basewnd; + return 1; +} + +#if 0//CUT +int WndCanvas::attachToWnd(HWND _hWnd) +{ + hWnd = _hWnd; + ASSERT(hWnd != NULL); + hdc = GetWindowDC(hWnd); + ASSERT(hdc != NULL); + return 1; +} +#endif + +PaintCanvas::PaintCanvas() +{ + hWnd = NULL; +} + +PaintCanvas::~PaintCanvas() +{ + + if (hdc != NULL) EndPaint(hWnd, &ps); + hdc = NULL; +} + +void PaintCanvas::getRcPaint(RECT *r) +{ + *r = ps.rcPaint; +} + +int PaintCanvas::beginPaint(BaseWnd *basewnd) +{ + hWnd = basewnd->gethWnd(); // NONPORTABLE + ASSERT(hWnd != NULL); + hdc = BeginPaint(hWnd, &ps); + ASSERT(hdc != NULL); + srcwnd = basewnd; + return 1; +} + +int PaintCanvas::beginPaint(HWND wnd) +{ + hWnd = wnd; // NONPORTABLE + ASSERT(hWnd != NULL); + hdc = BeginPaint(hWnd, &ps); + ASSERT(hdc != NULL); + srcwnd = NULL; + return 1; +} + +PaintBltCanvas::PaintBltCanvas() +{ + hWnd = NULL; + wnddc = NULL; + hbmp = NULL; + prevbmp = NULL; + bits = NULL; + fcoord = TRUE; + nonclient = FALSE; +} + +PaintBltCanvas::~PaintBltCanvas() +{ + RECT r; + + if (hdc == NULL) return ; + + ASSERT(srcwnd != NULL); + if (nonclient) //FG> nonclient painting fix + srcwnd->getNonClientRect(&r); + else + srcwnd->getClientRect(&r); + + // blt here + //GdiFlush(); + BitBlt(wnddc, r.left, r.top, r.right - r.left, r.bottom - r.top, hdc, 0, 0, SRCCOPY); + + //SelectClipRgn(hdc, NULL); + // kill the bitmap and its DC + SelectObject(hdc, prevbmp); + DeleteDC(hdc); + hdc = NULL; + DeleteObject(hbmp); + bits = NULL; + width = 0; + height = 0; + pitch = 0; + + EndPaint(hWnd, &ps); // end of wnddc + wnddc = NULL; +} + +//FG> nonclient painting fix +int PaintBltCanvas::beginPaintNC(BaseWnd *basewnd) +{ + nonclient = TRUE; + return beginPaint(basewnd); +} + +void PaintBltCanvas::getRcPaint(RECT *r) +{ + *r = ps.rcPaint; +} + +int PaintBltCanvas::beginPaint(BaseWnd *basewnd) +{ + + RECT r; + + if (nonclient) + basewnd->getNonClientRect(&r); //FG> nonclient painting fix + else + basewnd->getClientRect(&r); + + if (r.right - r.left <= 0 || r.bottom - r.top <= 0) return 0; + + hWnd = basewnd->gethWnd(); // NONPORTABLE + ASSERT(hWnd != NULL); + + BITMAPINFO bmi; + ZeroMemory(&bmi, sizeof bmi); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = r.right - r.left; + bmi.bmiHeader.biHeight = -(r.bottom - r.top); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + wnddc = BeginPaint(hWnd, &ps); + + ASSERT(wnddc != NULL); + + //GdiFlush(); + width = r.right - r.left; + height = -ABS(r.bottom - r.top); + pitch = width * 4; + hbmp = CreateDIBSection(wnddc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); + + if (hbmp == NULL) + { + EndPaint(hWnd, &ps); // end of wnddc + wnddc = NULL; + return 0; + } + + // create tha DC + hdc = CreateCompatibleDC(wnddc); + if (hdc == NULL) + { + DeleteObject(hbmp); + EndPaint(hWnd, &ps); // end of wnddc + wnddc = NULL; + return 0; + } + prevbmp = (HBITMAP)SelectObject(hdc, hbmp); + + RegionI clip(&ps.rcPaint); + + selectClipRgn(&clip); + + srcwnd = basewnd; + + return 1; +} + +void *PaintBltCanvas::getBits() +{ + return bits; +} + +MemCanvas::MemCanvas() +{} + +MemCanvas::~MemCanvas() +{ + DeleteDC(hdc); + hdc = NULL; +} + +int MemCanvas::createCompatible(Canvas *canvas) +{ + ASSERT(canvas != NULL); + ASSERT(canvas->getHDC() != NULL); + hdc = CreateCompatibleDC(canvas->getHDC()); + ASSERT(hdc != NULL); + srcwnd = canvas->getBaseWnd(); + return 1; +} + + +DCCanvas::DCCanvas(HDC clone, BaseWnd *srcWnd) +{ + if (clone != NULL) cloneDC(clone, srcWnd); +} + +DCCanvas::~DCCanvas() +{ + hdc = NULL; +} + +int DCCanvas::cloneDC(HDC clone, BaseWnd *srcWnd) +{ + ASSERT(clone != NULL); + hdc = clone; + srcwnd = srcWnd; + return 1; +} + +SysCanvas::SysCanvas() +{ + hdc = GetDC(NULL); +} + +SysCanvas::~SysCanvas() +{ + ReleaseDC(NULL, hdc); + hdc = NULL; +} + +DCBltCanvas::DCBltCanvas() +{ + origdc = NULL; + hbmp = prevbmp = NULL; +} + +DCBltCanvas::~DCBltCanvas() +{ + + commitDC(); + + // kill the bitmap and its DC + SelectObject(hdc, prevbmp); + DeleteDC(hdc); + hdc = NULL; + DeleteObject(hbmp); + + // don't kill origdc, it's been cloned +} + +int DCBltCanvas::setOrigDC(HDC neworigdc) +{ + // FG> allows custom draw on lists to be much faster + origdc = neworigdc; + return 1; +} + +int DCBltCanvas::commitDC(void) +{ + //FG + + if (origdc) + { + + RECT c; + + if (GetClipBox(origdc, &c) == NULLREGION) + c = rect; + + // shlap it down in its original spot + //GdiFlush(); + BitBlt(origdc, c.left, c.top, + c.right - c.left, c.bottom - c.top, hdc, c.left-rect.left, c.top-rect.top, SRCCOPY); + + } + + return 1; +} + +int DCBltCanvas::cloneDC(HDC clone, RECT *r, BaseWnd *srcWnd) +{ + origdc = clone; + + srcwnd = srcWnd; + + ASSERT(r != NULL); + rect = *r; + +#if 1 + BITMAPINFO bmi; + ZeroMemory(&bmi, sizeof bmi); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = r->right - r->left; + bmi.bmiHeader.biHeight = -ABS(r->bottom - r->top); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + hbmp = CreateDIBSection(origdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); + width = bmi.bmiHeader.biWidth; + height = ABS(bmi.bmiHeader.biHeight); + pitch = width * 4; +#else +hbmp = CreateCompatibleBitmap(clone, r->right - r->left, r->bottom - r->top); +#endif + ASSERT(hbmp != NULL); + + // create tha DC + hdc = CreateCompatibleDC(origdc); + prevbmp = (HBITMAP)SelectObject(hdc, hbmp); + + // adjust their rect for them + r->right -= r->left; + r->left = 0; + r->bottom -= r->top; + r->top = 0; + + return 1; +} + +DCExBltCanvas::DCExBltCanvas(HWND hWnd, HRGN hrgnClip, DWORD flags) : hwnd(hWnd) +{ + origdc = GetDCEx(hWnd, hrgnClip, flags); + RECT r; + GetWindowRect(hWnd, &r); + OffsetRect(&r, -r.left, -r.top); + cloneDC(origdc, &r); +} + +DCExBltCanvas::~DCExBltCanvas() +{ + commitDC(); + ReleaseDC(hwnd, origdc); + origdc=0; +} + + +BaseCloneCanvas::BaseCloneCanvas(ifc_canvas *cloner) +{ + if (cloner != NULL) clone(cloner); +} + +int BaseCloneCanvas::clone(ifc_canvas *cloner) +{ + ASSERTPR(hdc == NULL, "can't clone twice"); + hdc = cloner->getHDC(); + bits = cloner->getBits(); + cloner->getDim(&width, &height, &pitch); + // srcwnd = cloner->getBaseWnd(); + cloner->getOffsets(&xoffset, &yoffset); + + canvasFontInfo.face = cloner->getTextFont(); // just copies the pointer so be careful + canvasFontInfo.pointSize = cloner->getTextSize(); + canvasFontInfo.bold = cloner->getTextBold(); + canvasFontInfo.opaque = !!cloner->getTextOpaque(); + canvasFontInfo.underline = !!cloner->getTextUnderline(); + canvasFontInfo.italic = !!cloner->getTextItalic(); + canvasFontInfo.alignFlags = cloner->getTextAlign(); + canvasFontInfo.color = cloner->getTextColor(); + canvasFontInfo.bgColor = cloner->getTextBkColor(); + + return (hdc != NULL); +} + +BaseCloneCanvas::~BaseCloneCanvas() +{ + hdc = NULL; +} + +DDSurfaceCanvas::DDSurfaceCanvas(LPDIRECTDRAWSURFACE surface, int w, int h) +{ + surf = surface; + _w = w; + _h = h; + hdc = NULL; + bits = NULL; +} + +DDSurfaceCanvas::~DDSurfaceCanvas() +{ + if (isready()) + exit(); +} + +int DDSurfaceCanvas::isready() +{ + return bits != NULL; +} + +void DDSurfaceCanvas::enter() +{ + DDSURFACEDESC d = {sizeof(d), }; + if ((surf->Lock(NULL, &d, DDLOCK_WAIT, NULL)) != DD_OK) + return ; + + surf->GetDC(&hdc); + + bits = d.lpSurface; +} + +void DDSurfaceCanvas::exit() +{ + surf->ReleaseDC(hdc); + surf->Unlock(bits); + bits = NULL; + hdc = NULL; +} + + +#endif//WIN32 |