GR32_Backends_VCL.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. unit GR32_Backends_VCL;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Backend Extension for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Andre Beckedorf - metaException
  26. * [email protected]
  27. *
  28. * Portions created by the Initial Developer are Copyright (C) 2007-2009
  29. * the Initial Developer. All Rights Reserved.
  30. *
  31. * Contributor(s):
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$I GR32.inc}
  36. uses
  37. SysUtils, Classes, Windows, Graphics, GR32, GR32_Backends, GR32_Containers,
  38. GR32_Image, GR32_Backends_Generic, GR32_Paths;
  39. type
  40. { TGDIBackend }
  41. { This backend is the default backend on Windows.
  42. It uses the GDI to manage and provide the buffer and additional
  43. graphics sub system features. The backing buffer is kept in memory. }
  44. TGDIBackend = class(TCustomBackend, IPaintSupport,
  45. IBitmapContextSupport, IDeviceContextSupport,
  46. ITextSupport, IFontSupport, ICanvasSupport, ITextToPathSupport)
  47. private
  48. procedure FontChangedHandler(Sender: TObject);
  49. procedure CanvasChangedHandler(Sender: TObject);
  50. procedure CanvasChanged;
  51. procedure FontChanged;
  52. protected
  53. FBitmapInfo: TBitmapInfo;
  54. FBitmapHandle: HBITMAP;
  55. FHDC: HDC;
  56. FFont: TFont;
  57. FCanvas: TCanvas;
  58. FFontHandle: HFont;
  59. FMapHandle: THandle;
  60. FOnFontChange: TNotifyEvent;
  61. FOnCanvasChange: TNotifyEvent;
  62. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  63. procedure FinalizeSurface; override;
  64. procedure PrepareFileMapping(NewWidth, NewHeight: Integer); virtual;
  65. public
  66. constructor Create; override;
  67. destructor Destroy; override;
  68. procedure Changed; override;
  69. function Empty: Boolean; override;
  70. public
  71. { IPaintSupport }
  72. procedure ImageNeeded;
  73. procedure CheckPixmap;
  74. procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
  75. { IBitmapContextSupport }
  76. function GetBitmapInfo: TBitmapInfo;
  77. function GetBitmapHandle: THandle;
  78. property BitmapInfo: TBitmapInfo read GetBitmapInfo;
  79. property BitmapHandle: THandle read GetBitmapHandle;
  80. { IDeviceContextSupport }
  81. function GetHandle: HDC;
  82. procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
  83. procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
  84. procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
  85. property Handle: HDC read GetHandle;
  86. { ITextSupport }
  87. procedure Textout(X, Y: Integer; const Text: string); overload;
  88. procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: string); overload;
  89. procedure Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string); overload;
  90. function TextExtent(const Text: string): TSize;
  91. { IFontSupport }
  92. function GetOnFontChange: TNotifyEvent;
  93. procedure SetOnFontChange(Handler: TNotifyEvent);
  94. function GetFont: TFont;
  95. procedure SetFont(const Font: TFont);
  96. procedure UpdateFont;
  97. property Font: TFont read GetFont write SetFont;
  98. property OnFontChange: TNotifyEvent read FOnFontChange write FOnFontChange;
  99. { ITextToPathSupport }
  100. procedure TextToPath(Path: TCustomPath; const X, Y: TFloat; const Text: string); overload;
  101. procedure TextToPath(Path: TCustomPath; const DstRect: TFloatRect; const Text: string; Flags: Cardinal); overload;
  102. function MeasureText(const DstRect: TFloatRect; const Text: string; Flags: Cardinal): TFloatRect;
  103. { ICanvasSupport }
  104. function GetCanvasChange: TNotifyEvent;
  105. procedure SetCanvasChange(Handler: TNotifyEvent);
  106. function GetCanvas: TCanvas;
  107. procedure DeleteCanvas;
  108. function CanvasAllocated: Boolean;
  109. property Canvas: TCanvas read GetCanvas;
  110. property OnCanvasChange: TNotifyEvent read GetCanvasChange write SetCanvasChange;
  111. end;
  112. { TGDIMMFBackend }
  113. { Same as TGDIBackend but relies on memory mapped files or mapped swap space
  114. for the backing buffer. }
  115. TGDIMMFBackend = class(TGDIBackend)
  116. private
  117. FMapFileHandle: THandle;
  118. FMapIsTemporary: Boolean;
  119. FMapFileName: string;
  120. protected
  121. procedure PrepareFileMapping(NewWidth, NewHeight: Integer); override;
  122. public
  123. constructor Create(Owner: TBitmap32; IsTemporary: Boolean = True; const MapFileName: string = ''); virtual;
  124. destructor Destroy; override;
  125. end;
  126. { TGDIMemoryBackend }
  127. { A backend that keeps the backing buffer entirely in memory and offers
  128. IPaintSupport without allocating a GDI handle }
  129. TGDIMemoryBackend = class(TMemoryBackend, IPaintSupport, IDeviceContextSupport)
  130. private
  131. procedure DoPaintRect(ABuffer: TBitmap32; ARect: TRect; ACanvas: TCanvas);
  132. function GetHandle: HDC; // Dummy
  133. protected
  134. FBitmapInfo: TBitmapInfo;
  135. procedure InitializeSurface(NewWidth: Integer; NewHeight: Integer;
  136. ClearBuffer: Boolean); override;
  137. public
  138. constructor Create; override;
  139. { IPaintSupport }
  140. procedure ImageNeeded;
  141. procedure CheckPixmap;
  142. procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
  143. { IDeviceContextSupport }
  144. procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
  145. procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
  146. procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
  147. end;
  148. implementation
  149. uses
  150. GR32_Text_VCL;
  151. var
  152. StockFont: HFONT;
  153. { TGDIBackend }
  154. constructor TGDIBackend.Create;
  155. begin
  156. inherited;
  157. FillChar(FBitmapInfo, SizeOf(TBitmapInfo), 0);
  158. with FBitmapInfo.bmiHeader do
  159. begin
  160. biSize := SizeOf(TBitmapInfoHeader);
  161. biPlanes := 1;
  162. biBitCount := 32;
  163. biCompression := BI_RGB;
  164. end;
  165. FMapHandle := 0;
  166. FFont := TFont.Create;
  167. FFont.OnChange := FontChangedHandler;
  168. FFont.OwnerCriticalSection := @FLock;
  169. end;
  170. destructor TGDIBackend.Destroy;
  171. begin
  172. DeleteCanvas;
  173. FFont.Free;
  174. inherited;
  175. end;
  176. procedure TGDIBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  177. begin
  178. with FBitmapInfo.bmiHeader do
  179. begin
  180. biWidth := NewWidth;
  181. biHeight := -NewHeight;
  182. biSizeImage := NewWidth * NewHeight * 4;
  183. end;
  184. PrepareFileMapping(NewWidth, NewHeight);
  185. FBitmapHandle := CreateDIBSection(0, FBitmapInfo, DIB_RGB_COLORS, Pointer(FBits), FMapHandle, 0);
  186. if FBits = nil then
  187. raise EBackend.Create(RCStrCannotAllocateDIBHandle);
  188. FHDC := CreateCompatibleDC(0);
  189. if FHDC = 0 then
  190. begin
  191. DeleteObject(FBitmapHandle);
  192. FBitmapHandle := 0;
  193. FBits := nil;
  194. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  195. end;
  196. if SelectObject(FHDC, FBitmapHandle) = 0 then
  197. begin
  198. DeleteDC(FHDC);
  199. DeleteObject(FBitmapHandle);
  200. FHDC := 0;
  201. FBitmapHandle := 0;
  202. FBits := nil;
  203. raise EBackend.Create(RCStrCannotSelectAnObjectIntoDC);
  204. end;
  205. end;
  206. function TGDIBackend.MeasureText(const DstRect: TFloatRect; const Text: string;
  207. Flags: Cardinal): TFloatRect;
  208. begin
  209. Result := GR32_Text_VCL.MeasureText(Font.Handle, DstRect, Text, Flags);
  210. end;
  211. procedure TGDIBackend.FinalizeSurface;
  212. begin
  213. if FHDC <> 0 then DeleteDC(FHDC);
  214. FHDC := 0;
  215. if FBitmapHandle <> 0 then DeleteObject(FBitmapHandle);
  216. FBitmapHandle := 0;
  217. FBits := nil;
  218. end;
  219. procedure TGDIBackend.DeleteCanvas;
  220. begin
  221. if Assigned(FCanvas) then
  222. begin
  223. FCanvas.Handle := 0;
  224. FCanvas.Free;
  225. FCanvas := nil;
  226. end;
  227. end;
  228. procedure TGDIBackend.PrepareFileMapping(NewWidth, NewHeight: Integer);
  229. begin
  230. // to be implemented by descendants
  231. end;
  232. procedure TGDIBackend.Changed;
  233. begin
  234. if FCanvas <> nil then FCanvas.Handle := Self.Handle;
  235. inherited;
  236. end;
  237. procedure TGDIBackend.CanvasChanged;
  238. begin
  239. if Assigned(FOnCanvasChange) then
  240. FOnCanvasChange(Self);
  241. end;
  242. procedure TGDIBackend.FontChanged;
  243. begin
  244. if Assigned(FOnFontChange) then
  245. FOnFontChange(Self);
  246. end;
  247. function TGDIBackend.TextExtent(const Text: string): TSize;
  248. var
  249. DC: HDC;
  250. OldFont: HGDIOBJ;
  251. begin
  252. UpdateFont;
  253. Result.cX := 0;
  254. Result.cY := 0;
  255. if Handle <> 0 then
  256. Windows.GetTextExtentPoint32(Handle, PChar(Text), Length(Text), Result)
  257. else
  258. begin
  259. StockBitmap.Canvas.Lock;
  260. try
  261. DC := StockBitmap.Canvas.Handle;
  262. OldFont := SelectObject(DC, Font.Handle);
  263. Windows.GetTextExtentPoint32(DC, PChar(Text), Length(Text), Result);
  264. SelectObject(DC, OldFont);
  265. finally
  266. StockBitmap.Canvas.Unlock;
  267. end;
  268. end;
  269. end;
  270. procedure TGDIBackend.Textout(X, Y: Integer; const Text: string);
  271. var
  272. Extent: TSize;
  273. begin
  274. UpdateFont;
  275. if not FOwner.MeasuringMode then
  276. begin
  277. if FOwner.Clipping then
  278. ExtTextout(Handle, X, Y, ETO_CLIPPED, @FOwner.ClipRect, PChar(Text), Length(Text), nil)
  279. else
  280. ExtTextout(Handle, X, Y, 0, nil, PChar(Text), Length(Text), nil);
  281. end;
  282. Extent := TextExtent(Text);
  283. FOwner.Changed(MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1));
  284. end;
  285. procedure TGDIBackend.Textout(X, Y: Integer; const ClipRect: TRect; const Text: string);
  286. var
  287. Extent: TSize;
  288. begin
  289. UpdateFont;
  290. if not FOwner.MeasuringMode then
  291. ExtTextout(Handle, X, Y, ETO_CLIPPED, @ClipRect, PChar(Text), Length(Text), nil);
  292. Extent := TextExtent(Text);
  293. FOwner.Changed(MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1));
  294. end;
  295. procedure TGDIBackend.TextToPath(Path: TCustomPath; const X, Y: TFloat; const Text: string);
  296. var
  297. R: TFloatRect;
  298. begin
  299. R := FloatRect(X, Y, X, Y);
  300. GR32_Text_VCL.TextToPath(Font.Handle, Path, R, Text, 0);
  301. end;
  302. procedure TGDIBackend.TextToPath(Path: TCustomPath; const DstRect: TFloatRect;
  303. const Text: string; Flags: Cardinal);
  304. begin
  305. GR32_Text_VCL.TextToPath(Font.Handle, Path, DstRect, Text, Flags);
  306. end;
  307. procedure TGDIBackend.UpdateFont;
  308. begin
  309. if (FFontHandle = 0) and (Handle <> 0) then
  310. begin
  311. SelectObject(Handle, Font.Handle);
  312. SetTextColor(Handle, ColorToRGB(Font.Color));
  313. SetBkMode(Handle, Windows.TRANSPARENT);
  314. FFontHandle := Font.Handle;
  315. end
  316. else
  317. begin
  318. SelectObject(Handle, FFontHandle);
  319. SetTextColor(Handle, ColorToRGB(Font.Color));
  320. SetBkMode(Handle, Windows.TRANSPARENT);
  321. end;
  322. end;
  323. procedure TGDIBackend.Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string);
  324. begin
  325. UpdateFont;
  326. if not FOwner.MeasuringMode then
  327. DrawText(Handle, PChar(Text), Length(Text), DstRect, Flags);
  328. FOwner.Changed(DstRect);
  329. end;
  330. procedure TGDIBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
  331. begin
  332. StretchDIBits(
  333. hDst, DstX, DstY, FOwner.Width, FOwner.Height,
  334. 0, 0, FOwner.Width, FOwner.Height, Bits, FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  335. end;
  336. procedure TGDIBackend.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
  337. begin
  338. StretchBlt(
  339. hDst,
  340. DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Handle,
  341. SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
  342. end;
  343. function TGDIBackend.GetBitmapHandle: THandle;
  344. begin
  345. Result := FBitmapHandle;
  346. end;
  347. function TGDIBackend.GetBitmapInfo: TBitmapInfo;
  348. begin
  349. Result := FBitmapInfo;
  350. end;
  351. function TGDIBackend.GetCanvas: TCanvas;
  352. begin
  353. if not Assigned(FCanvas) then
  354. begin
  355. FCanvas := TCanvas.Create;
  356. FCanvas.Handle := Handle;
  357. FCanvas.OnChange := CanvasChangedHandler;
  358. end;
  359. Result := FCanvas;
  360. end;
  361. function TGDIBackend.GetCanvasChange: TNotifyEvent;
  362. begin
  363. Result := FOnCanvasChange;
  364. end;
  365. function TGDIBackend.GetFont: TFont;
  366. begin
  367. Result := FFont;
  368. end;
  369. function TGDIBackend.GetHandle: HDC;
  370. begin
  371. Result := FHDC;
  372. end;
  373. function TGDIBackend.GetOnFontChange: TNotifyEvent;
  374. begin
  375. Result := FOnFontChange;
  376. end;
  377. procedure TGDIBackend.SetCanvasChange(Handler: TNotifyEvent);
  378. begin
  379. FOnCanvasChange := Handler;
  380. end;
  381. procedure TGDIBackend.SetFont(const Font: TFont);
  382. begin
  383. FFont.Assign(Font);
  384. FontChanged;
  385. end;
  386. procedure TGDIBackend.SetOnFontChange(Handler: TNotifyEvent);
  387. begin
  388. FOnFontChange := Handler;
  389. end;
  390. procedure TGDIBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
  391. begin
  392. if FOwner.Empty then Exit;
  393. if not FOwner.MeasuringMode then
  394. StretchBlt(Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
  395. DstRect.Bottom - DstRect.Top, hSrc, SrcRect.Left, SrcRect.Top,
  396. SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
  397. FOwner.Changed(DstRect);
  398. end;
  399. function TGDIBackend.CanvasAllocated: Boolean;
  400. begin
  401. Result := Assigned(FCanvas);
  402. end;
  403. function TGDIBackend.Empty: Boolean;
  404. begin
  405. Result := FBitmapHandle = 0;
  406. end;
  407. procedure TGDIBackend.FontChangedHandler(Sender: TObject);
  408. begin
  409. if FFontHandle <> 0 then
  410. begin
  411. if Handle <> 0 then SelectObject(Handle, StockFont);
  412. FFontHandle := 0;
  413. end;
  414. FontChanged;
  415. end;
  416. procedure TGDIBackend.CanvasChangedHandler(Sender: TObject);
  417. begin
  418. CanvasChanged;
  419. end;
  420. { IPaintSupport }
  421. procedure TGDIBackend.ImageNeeded;
  422. begin
  423. end;
  424. procedure TGDIBackend.CheckPixmap;
  425. begin
  426. end;
  427. procedure TGDIBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList;
  428. ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
  429. var
  430. i: Integer;
  431. begin
  432. if AInvalidRects.Count > 0 then
  433. for i := 0 to AInvalidRects.Count - 1 do
  434. with AInvalidRects[i]^ do
  435. BitBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top, ABuffer.Handle, Left, Top, SRCCOPY)
  436. else
  437. with APaintBox.GetViewportRect do
  438. BitBlt(ACanvas.Handle, Left, Top, Right - Left, Bottom - Top, ABuffer.Handle, Left, Top, SRCCOPY);
  439. end;
  440. { TGDIMMFBackend }
  441. constructor TGDIMMFBackend.Create(Owner: TBitmap32; IsTemporary: Boolean = True; const MapFileName: string = '');
  442. begin
  443. FMapFileName := MapFileName;
  444. FMapIsTemporary := IsTemporary;
  445. TMMFBackend.InitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  446. inherited Create(Owner);
  447. end;
  448. destructor TGDIMMFBackend.Destroy;
  449. begin
  450. TMMFBackend.DeinitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  451. inherited;
  452. end;
  453. procedure TGDIMMFBackend.PrepareFileMapping(NewWidth, NewHeight: Integer);
  454. begin
  455. TMMFBackend.CreateFileMapping(FMapHandle, FMapFileHandle, FMapFileName, FMapIsTemporary, NewWidth, NewHeight);
  456. end;
  457. { TGDIMemoryBackend }
  458. constructor TGDIMemoryBackend.Create;
  459. begin
  460. inherited;
  461. FillChar(FBitmapInfo, SizeOf(TBitmapInfo), 0);
  462. with FBitmapInfo.bmiHeader do
  463. begin
  464. biSize := SizeOf(TBitmapInfoHeader);
  465. biPlanes := 1;
  466. biBitCount := 32;
  467. biCompression := BI_RGB;
  468. biXPelsPerMeter := 96;
  469. biYPelsPerMeter := 96;
  470. biClrUsed := 0;
  471. end;
  472. end;
  473. procedure TGDIMemoryBackend.InitializeSurface(NewWidth, NewHeight: Integer;
  474. ClearBuffer: Boolean);
  475. begin
  476. inherited;
  477. with FBitmapInfo.bmiHeader do
  478. begin
  479. biWidth := NewWidth;
  480. biHeight := -NewHeight;
  481. end;
  482. end;
  483. procedure TGDIMemoryBackend.ImageNeeded;
  484. begin
  485. end;
  486. procedure TGDIMemoryBackend.CheckPixmap;
  487. begin
  488. end;
  489. procedure TGDIMemoryBackend.DoPaintRect(ABuffer: TBitmap32;
  490. ARect: TRect; ACanvas: TCanvas);
  491. var
  492. Bitmap : HBITMAP;
  493. DeviceContext : HDC;
  494. Buffer : Pointer;
  495. OldObject : HGDIOBJ;
  496. begin
  497. if SetDIBitsToDevice(ACanvas.Handle, ARect.Left, ARect.Top, ARect.Right -
  498. ARect.Left, ARect.Bottom - ARect.Top, ARect.Left, ARect.Top, 0,
  499. ARect.Bottom - ARect.Top, ABuffer.Bits, FBitmapInfo, DIB_RGB_COLORS) = 0 then
  500. begin
  501. // create compatible device context
  502. DeviceContext := CreateCompatibleDC(ACanvas.Handle);
  503. if DeviceContext <> 0 then
  504. try
  505. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS,
  506. Buffer, 0, 0);
  507. if Bitmap <> 0 then
  508. begin
  509. OldObject := SelectObject(DeviceContext, Bitmap);
  510. try
  511. Move(ABuffer.Bits^, Buffer^, FBitmapInfo.bmiHeader.biWidth *
  512. FBitmapInfo.bmiHeader.biHeight * SizeOf(Cardinal));
  513. BitBlt(ACanvas.Handle, ARect.Left, ARect.Top, ARect.Right -
  514. ARect.Left, ARect.Bottom - ARect.Top, DeviceContext, 0, 0, SRCCOPY);
  515. finally
  516. if OldObject <> 0 then
  517. SelectObject(DeviceContext, OldObject);
  518. DeleteObject(Bitmap);
  519. end;
  520. end else
  521. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  522. finally
  523. DeleteDC(DeviceContext);
  524. end;
  525. end;
  526. end;
  527. procedure TGDIMemoryBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
  528. begin
  529. if FOwner.Empty then Exit;
  530. if not FOwner.MeasuringMode then
  531. raise EBackend.Create('Not supported!');
  532. FOwner.Changed(DstRect);
  533. end;
  534. procedure TGDIMemoryBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
  535. var
  536. Bitmap : HBITMAP;
  537. DeviceContext : HDC;
  538. Buffer : Pointer;
  539. OldObject : HGDIOBJ;
  540. begin
  541. if SetDIBitsToDevice(hDst, DstX, DstY, FOwner.Width, FOwner.Height, 0, 0, 0,
  542. FOwner.Height, FBits, FBitmapInfo, DIB_RGB_COLORS) = 0 then
  543. begin
  544. // create compatible device context
  545. DeviceContext := CreateCompatibleDC(hDst);
  546. if DeviceContext <> 0 then
  547. try
  548. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS,
  549. Buffer, 0, 0);
  550. if Bitmap <> 0 then
  551. begin
  552. OldObject := SelectObject(DeviceContext, Bitmap);
  553. try
  554. Move(FBits^, Buffer^, FBitmapInfo.bmiHeader.biWidth *
  555. FBitmapInfo.bmiHeader.biHeight * SizeOf(Cardinal));
  556. BitBlt(hDst, DstX, DstY, FOwner.Width, FOwner.Height, DeviceContext,
  557. 0, 0, SRCCOPY);
  558. finally
  559. if OldObject <> 0 then
  560. SelectObject(DeviceContext, OldObject);
  561. DeleteObject(Bitmap);
  562. end;
  563. end else
  564. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  565. finally
  566. DeleteDC(DeviceContext);
  567. end;
  568. end;
  569. end;
  570. procedure TGDIMemoryBackend.DrawTo(hDst: HDC;
  571. const DstRect, SrcRect: TRect);
  572. var
  573. Bitmap : HBITMAP;
  574. DeviceContext : HDC;
  575. Buffer : Pointer;
  576. OldObject : HGDIOBJ;
  577. begin
  578. if SetDIBitsToDevice(hDst, DstRect.Left, DstRect.Top,
  579. DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, SrcRect.Left,
  580. SrcRect.Top, 0, SrcRect.Bottom - SrcRect.Top, FBits, FBitmapInfo,
  581. DIB_RGB_COLORS) = 0 then
  582. begin
  583. // create compatible device context
  584. DeviceContext := CreateCompatibleDC(hDst);
  585. if DeviceContext <> 0 then
  586. try
  587. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS,
  588. Buffer, 0, 0);
  589. if Bitmap <> 0 then
  590. begin
  591. OldObject := SelectObject(DeviceContext, Bitmap);
  592. try
  593. Move(FBits^, Buffer^, FBitmapInfo.bmiHeader.biWidth *
  594. FBitmapInfo.bmiHeader.biHeight * SizeOf(Cardinal));
  595. BitBlt(hDst, DstRect.Left, DstRect.Top, DstRect.Right -
  596. DstRect.Left, DstRect.Bottom - DstRect.Top, DeviceContext, 0, 0, SRCCOPY);
  597. finally
  598. if OldObject <> 0 then
  599. SelectObject(DeviceContext, OldObject);
  600. DeleteObject(Bitmap);
  601. end;
  602. end else
  603. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  604. finally
  605. DeleteDC(DeviceContext);
  606. end;
  607. end;
  608. end;
  609. function TGDIMemoryBackend.GetHandle: HDC;
  610. begin
  611. Result := 0;
  612. end;
  613. procedure TGDIMemoryBackend.DoPaint(ABuffer: TBitmap32;
  614. AInvalidRects: TRectList; ACanvas: TCanvas; APaintBox: TCustomPaintBox32);
  615. var
  616. i : Integer;
  617. begin
  618. if AInvalidRects.Count > 0 then
  619. for i := 0 to AInvalidRects.Count - 1 do
  620. DoPaintRect(ABuffer, AInvalidRects[i]^, ACanvas)
  621. else
  622. DoPaintRect(ABuffer, APaintBox.GetViewportRect, ACanvas);
  623. end;
  624. initialization
  625. StockFont := GetStockObject(SYSTEM_FONT);
  626. finalization
  627. end.