GR32_Backends_VCL.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  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. {$include GR32.inc}
  36. uses
  37. System.SysUtils, System.Classes,
  38. WinAPI.Windows,
  39. VCL.Graphics, VCL.Controls,
  40. GR32,
  41. GR32_Backends,
  42. GR32_Backends_Generic,
  43. GR32.Text.Types,
  44. GR32_Containers,
  45. GR32_Paths;
  46. type
  47. { TGDIBackend }
  48. { This backend is the default backend on Windows.
  49. It uses the GDI to manage and provide the buffer and additional
  50. graphics sub system features. The backing buffer is kept in memory. }
  51. TGDIBackend = class(TCustomBackend,
  52. IPaintSupport,
  53. IBitmapContextSupport,
  54. IDeviceContextSupport,
  55. ITextSupport,
  56. IFontSupport,
  57. ICanvasSupport,
  58. ITextToPathSupport,
  59. IUpdateRectSupport,
  60. IFontHintingSupport
  61. )
  62. private
  63. procedure FontChangedHandler(Sender: TObject);
  64. procedure CanvasChangedHandler(Sender: TObject);
  65. procedure CanvasChanged;
  66. procedure FontChanged;
  67. protected
  68. FBitmapInfo: TBitmapInfo;
  69. FBitmapHandle: HBITMAP;
  70. FHDC: HDC;
  71. FFont: TFont;
  72. FCanvas: TCanvas;
  73. FFontHandle: HFont;
  74. FMapHandle: THandle;
  75. FOnFontChange: TNotifyEvent;
  76. FOnCanvasChange: TNotifyEvent;
  77. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  78. procedure FinalizeSurface; override;
  79. procedure PrepareFileMapping(NewWidth, NewHeight: Integer); virtual;
  80. public
  81. constructor Create; override;
  82. destructor Destroy; override;
  83. procedure Changed; override;
  84. function Empty: Boolean; override;
  85. public
  86. { IPaintSupport }
  87. procedure ImageNeeded;
  88. procedure CheckPixmap;
  89. procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas); overload;
  90. procedure DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas); overload;
  91. { IBitmapContextSupport }
  92. function GetBitmapInfo: TBitmapInfo;
  93. function GetBitmapHandle: THandle;
  94. property BitmapInfo: TBitmapInfo read GetBitmapInfo;
  95. property BitmapHandle: THandle read GetBitmapHandle;
  96. { IDeviceContextSupport }
  97. function GetHandle: HDC;
  98. procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
  99. procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
  100. procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
  101. property Handle: HDC read GetHandle;
  102. { ITextSupport }
  103. procedure Textout(X, Y: Integer; const Text: string); overload;
  104. procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: string); overload;
  105. procedure Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string); overload;
  106. function TextExtent(const Text: string): TSize;
  107. { IFontSupport }
  108. function GetOnFontChange: TNotifyEvent;
  109. procedure SetOnFontChange(Handler: TNotifyEvent);
  110. function GetFont: TFont;
  111. procedure SetFont(const Font: TFont);
  112. procedure UpdateFont;
  113. property Font: TFont read GetFont write SetFont;
  114. property OnFontChange: TNotifyEvent read FOnFontChange write FOnFontChange;
  115. { ITextToPathSupport }
  116. procedure TextToPath(Path: TCustomPath; const X, Y: TFloat; const Text: string); overload;
  117. procedure TextToPath(Path: TCustomPath; const DstRect: TFloatRect; const Text: string; Flags: Cardinal); overload;
  118. function MeasureText(const DstRect: TFloatRect; const Text: string; Flags: Cardinal): TFloatRect;
  119. { ICanvasSupport }
  120. function GetCanvasChange: TNotifyEvent;
  121. procedure SetCanvasChange(Handler: TNotifyEvent);
  122. function GetCanvas: TCanvas;
  123. procedure DeleteCanvas;
  124. function CanvasAllocated: Boolean;
  125. property Canvas: TCanvas read GetCanvas;
  126. property OnCanvasChange: TNotifyEvent read GetCanvasChange write SetCanvasChange;
  127. { IUpdateRectSupport }
  128. procedure InvalidateRect(AControl: TWinControl; const ARect: TRect);
  129. procedure GetUpdateRects(AControl: TWinControl; AUpdateRects: TRectList; AReservedCapacity: integer; var AFullUpdate: boolean);
  130. { IFontHintingSupport }
  131. function GetHinting: TTextHinting;
  132. procedure SetHinting(Value: TTextHinting);
  133. end;
  134. { TGDIMMFBackend }
  135. { Same as TGDIBackend but relies on memory mapped files or mapped swap space
  136. for the backing buffer. }
  137. TGDIMMFBackend = class(TGDIBackend)
  138. private
  139. FMapFileHandle: THandle;
  140. FMapIsTemporary: Boolean;
  141. FMapFileName: string;
  142. protected
  143. procedure PrepareFileMapping(NewWidth, NewHeight: Integer); override;
  144. public
  145. constructor Create(Owner: TBitmap32; IsTemporary: Boolean = True; const MapFileName: string = ''); virtual;
  146. destructor Destroy; override;
  147. end;
  148. { TGDIMemoryBackend }
  149. { A backend that keeps the backing buffer entirely in memory and offers
  150. IPaintSupport without allocating a GDI handle }
  151. TGDIMemoryBackend = class(TMemoryBackend, IPaintSupport, IDeviceContextSupport)
  152. private
  153. procedure DoPaintRect(ABuffer: TBitmap32; ARect: TRect; ACanvas: TCanvas);
  154. function GetHandle: HDC; // Dummy
  155. protected
  156. FBitmapInfo: TBitmapInfo;
  157. procedure InitializeSurface(NewWidth: Integer; NewHeight: Integer;
  158. ClearBuffer: Boolean); override;
  159. public
  160. constructor Create; override;
  161. { IPaintSupport }
  162. procedure ImageNeeded;
  163. procedure CheckPixmap;
  164. procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas); overload;
  165. procedure DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas); overload;
  166. { IDeviceContextSupport }
  167. procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
  168. procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
  169. procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
  170. end;
  171. implementation
  172. uses
  173. System.Math,
  174. System.Types,
  175. GR32.Text.Win;
  176. var
  177. StockFont: HFONT;
  178. { TGDIBackend }
  179. constructor TGDIBackend.Create;
  180. begin
  181. inherited;
  182. FBitmapInfo := Default(TBitmapInfo);
  183. FBitmapInfo.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
  184. FBitmapInfo.bmiHeader.biPlanes := 1;
  185. FBitmapInfo.bmiHeader.biBitCount := 32;
  186. FBitmapInfo.bmiHeader.biCompression := BI_RGB;
  187. FMapHandle := 0;
  188. FFont := TFont.Create;
  189. FFont.OnChange := FontChangedHandler;
  190. FFont.OwnerCriticalSection := @FLock;
  191. end;
  192. destructor TGDIBackend.Destroy;
  193. begin
  194. DeleteCanvas;
  195. FFont.Free;
  196. inherited;
  197. end;
  198. procedure TGDIBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  199. begin
  200. FBitmapInfo.bmiHeader.biWidth := NewWidth;
  201. FBitmapInfo.bmiHeader.biHeight := -NewHeight; // Bottom-up DIB
  202. FBitmapInfo.bmiHeader.biSizeImage := NewWidth * NewHeight * SizeOf(SizeOf(TRGBQuad));
  203. PrepareFileMapping(NewWidth, NewHeight);
  204. FBitmapHandle := CreateDIBSection(0, FBitmapInfo, DIB_RGB_COLORS, Pointer(FBits), FMapHandle, 0);
  205. if FBits = nil then
  206. raise EBackend.Create(RCStrCannotAllocateDIBHandle);
  207. FHDC := CreateCompatibleDC(0);
  208. if FHDC = 0 then
  209. begin
  210. DeleteObject(FBitmapHandle);
  211. FBitmapHandle := 0;
  212. FBits := nil;
  213. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  214. end;
  215. if SelectObject(FHDC, FBitmapHandle) = 0 then
  216. begin
  217. DeleteDC(FHDC);
  218. DeleteObject(FBitmapHandle);
  219. FHDC := 0;
  220. FBitmapHandle := 0;
  221. FBits := nil;
  222. raise EBackend.Create(RCStrCannotSelectAnObjectIntoDC);
  223. end;
  224. end;
  225. function TGDIBackend.MeasureText(const DstRect: TFloatRect; const Text: string; Flags: Cardinal): TFloatRect;
  226. begin
  227. Result := TextToolsWin.MeasureText(Font.Handle, DstRect, Text, Flags);
  228. end;
  229. procedure TGDIBackend.FinalizeSurface;
  230. begin
  231. if FHDC <> 0 then
  232. DeleteDC(FHDC);
  233. FHDC := 0;
  234. if FBitmapHandle <> 0 then
  235. DeleteObject(FBitmapHandle);
  236. FBitmapHandle := 0;
  237. FBits := nil;
  238. end;
  239. procedure TGDIBackend.DeleteCanvas;
  240. begin
  241. if (FCanvas <> nil) then
  242. begin
  243. FCanvas.Handle := 0;
  244. FCanvas.Free;
  245. FCanvas := nil;
  246. end;
  247. end;
  248. procedure TGDIBackend.PrepareFileMapping(NewWidth, NewHeight: Integer);
  249. begin
  250. // to be implemented by descendants
  251. end;
  252. procedure TGDIBackend.Changed;
  253. begin
  254. if FCanvas <> nil then
  255. FCanvas.Handle := Self.Handle;
  256. inherited;
  257. end;
  258. procedure TGDIBackend.CanvasChanged;
  259. begin
  260. if Assigned(FOnCanvasChange) then
  261. FOnCanvasChange(Self);
  262. end;
  263. procedure TGDIBackend.FontChanged;
  264. begin
  265. if Assigned(FOnFontChange) then
  266. FOnFontChange(Self);
  267. end;
  268. function TGDIBackend.TextExtent(const Text: string): TSize;
  269. var
  270. DC: HDC;
  271. OldFont: HGDIOBJ;
  272. begin
  273. UpdateFont;
  274. Result.cX := 0;
  275. Result.cY := 0;
  276. if Handle <> 0 then
  277. WinAPI.Windows.GetTextExtentPoint32(Handle, PChar(Text), Length(Text), Result)
  278. else
  279. begin
  280. StockBitmap.Canvas.Lock;
  281. try
  282. DC := StockBitmap.Canvas.Handle;
  283. OldFont := SelectObject(DC, Font.Handle);
  284. WinAPI.Windows.GetTextExtentPoint32(DC, PChar(Text), Length(Text), Result);
  285. SelectObject(DC, OldFont);
  286. finally
  287. StockBitmap.Canvas.Unlock;
  288. end;
  289. end;
  290. end;
  291. procedure TGDIBackend.Textout(X, Y: Integer; const Text: string);
  292. var
  293. Extent: TSize;
  294. begin
  295. UpdateFont;
  296. if not FOwner.MeasuringMode then
  297. begin
  298. if FOwner.Clipping then
  299. ExtTextout(Handle, X, Y, ETO_CLIPPED, @FOwner.ClipRect, PChar(Text), Length(Text), nil)
  300. else
  301. ExtTextout(Handle, X, Y, 0, nil, PChar(Text), Length(Text), nil);
  302. end;
  303. Extent := TextExtent(Text);
  304. FOwner.Changed(MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1));
  305. end;
  306. procedure TGDIBackend.Textout(X, Y: Integer; const ClipRect: TRect; const Text: string);
  307. var
  308. Extent: TSize;
  309. begin
  310. UpdateFont;
  311. if not FOwner.MeasuringMode then
  312. ExtTextout(Handle, X, Y, ETO_CLIPPED, @ClipRect, PChar(Text), Length(Text), nil);
  313. Extent := TextExtent(Text);
  314. FOwner.Changed(MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1));
  315. end;
  316. procedure TGDIBackend.TextToPath(Path: TCustomPath; const X, Y: TFloat; const Text: string);
  317. var
  318. R: TFloatRect;
  319. begin
  320. R := FloatRect(X, Y, X, Y);
  321. TextToolsWin.TextToPath(Font.Handle, Path, R, Text, 0);
  322. end;
  323. procedure TGDIBackend.TextToPath(Path: TCustomPath; const DstRect: TFloatRect;
  324. const Text: string; Flags: Cardinal);
  325. begin
  326. TextToolsWin.TextToPath(Font.Handle, Path, DstRect, Text, Flags);
  327. end;
  328. procedure TGDIBackend.UpdateFont;
  329. begin
  330. if (FFontHandle = 0) and (Handle <> 0) then
  331. begin
  332. SelectObject(Handle, Font.Handle);
  333. SetTextColor(Handle, ColorToRGB(Font.Color));
  334. SetBkMode(Handle, WinAPI.Windows.TRANSPARENT);
  335. FFontHandle := Font.Handle;
  336. end
  337. else
  338. begin
  339. SelectObject(Handle, FFontHandle);
  340. SetTextColor(Handle, ColorToRGB(Font.Color));
  341. SetBkMode(Handle, WinAPI.Windows.TRANSPARENT);
  342. end;
  343. end;
  344. procedure TGDIBackend.Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string);
  345. begin
  346. UpdateFont;
  347. if not FOwner.MeasuringMode then
  348. DrawText(Handle, PChar(Text), Length(Text), DstRect, Flags);
  349. FOwner.Changed(DstRect);
  350. end;
  351. procedure TGDIBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
  352. begin
  353. StretchDIBits(
  354. hDst, DstX, DstY, FOwner.Width, FOwner.Height,
  355. 0, 0, FOwner.Width, FOwner.Height, Bits, FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  356. end;
  357. procedure TGDIBackend.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
  358. begin
  359. StretchBlt(
  360. hDst,
  361. DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Handle,
  362. SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
  363. end;
  364. function TGDIBackend.GetBitmapHandle: THandle;
  365. begin
  366. Result := FBitmapHandle;
  367. end;
  368. function TGDIBackend.GetBitmapInfo: TBitmapInfo;
  369. begin
  370. Result := FBitmapInfo;
  371. end;
  372. function TGDIBackend.GetCanvas: TCanvas;
  373. begin
  374. if (FCanvas = nil) then
  375. begin
  376. FCanvas := TCanvas.Create;
  377. FCanvas.Handle := Handle;
  378. FCanvas.OnChange := CanvasChangedHandler;
  379. end;
  380. Result := FCanvas;
  381. end;
  382. function TGDIBackend.GetCanvasChange: TNotifyEvent;
  383. begin
  384. Result := FOnCanvasChange;
  385. end;
  386. function TGDIBackend.GetFont: TFont;
  387. begin
  388. Result := FFont;
  389. end;
  390. function TGDIBackend.GetHandle: HDC;
  391. begin
  392. Result := FHDC;
  393. end;
  394. function TGDIBackend.GetOnFontChange: TNotifyEvent;
  395. begin
  396. Result := FOnFontChange;
  397. end;
  398. procedure TGDIBackend.InvalidateRect(AControl: TWinControl; const ARect: TRect);
  399. begin
  400. if (AControl.HandleAllocated) then
  401. WinAPI.Windows.InvalidateRect(AControl.Handle, @ARect, False);
  402. end;
  403. procedure TGDIBackend.GetUpdateRects(AControl: TWinControl; AUpdateRects: TRectList; AReservedCapacity: integer; var AFullUpdate: boolean);
  404. var
  405. RegionType: integer;
  406. UpdateRegion: HRGN;
  407. RegionSize: integer;
  408. RegionData: PRgnData;
  409. r: TRect;
  410. i: integer;
  411. begin
  412. UpdateRegion := CreateRectRgn(0,0,0,0);
  413. try
  414. RegionType := GetUpdateRgn(AControl.Handle, UpdateRegion, False);
  415. case RegionType of
  416. COMPLEXREGION:
  417. begin
  418. RegionSize := GetRegionData(UpdateRegion, 0, nil);
  419. if (RegionSize > 0) then
  420. begin
  421. GetMem(RegionData, RegionSize);
  422. try
  423. {$IFOPT C+} // ST: IF ASSERTIONS ON
  424. RegionSize :=
  425. {$ENDIF}
  426. GetRegionData(UpdateRegion, RegionSize, RegionData);
  427. Assert(RegionSize <> 0);
  428. // Final count is known so set capacity to avoid reallocation
  429. AUpdateRects.Capacity := Max(AUpdateRects.Capacity, AUpdateRects.Count + AReservedCapacity + integer(RegionData.rdh.nCount));
  430. for i := 0 to RegionData.rdh.nCount-1 do
  431. AUpdateRects.Add(PPolyRects(@RegionData.Buffer)[i]);
  432. finally
  433. FreeMem(RegionData);
  434. end;
  435. end;
  436. end;
  437. NULLREGION:
  438. AFullUpdate := True;
  439. SIMPLEREGION:
  440. begin
  441. GetUpdateRect(AControl.Handle, r, False);
  442. if (GR32.EqualRect(r, AControl.ClientRect)) then
  443. AFullUpdate := True
  444. else
  445. begin
  446. AUpdateRects.Capacity := Max(AUpdateRects.Capacity, AUpdateRects.Count + AReservedCapacity + 1);
  447. AUpdateRects.Add(r);
  448. end;
  449. end
  450. else
  451. // Error - Ignore it
  452. AFullUpdate := True
  453. end;
  454. finally
  455. DeleteObject(UpdateRegion);
  456. end;
  457. end;
  458. function TGDIBackend.GetHinting: TTextHinting;
  459. begin
  460. Result := TextToolsWin.GetHinting;
  461. end;
  462. procedure TGDIBackend.SetHinting(Value: TTextHinting);
  463. begin
  464. TextToolsWin.SetHinting(Value);
  465. end;
  466. procedure TGDIBackend.SetCanvasChange(Handler: TNotifyEvent);
  467. begin
  468. FOnCanvasChange := Handler;
  469. end;
  470. procedure TGDIBackend.SetFont(const Font: TFont);
  471. begin
  472. FFont.Assign(Font);
  473. FontChanged;
  474. end;
  475. procedure TGDIBackend.SetOnFontChange(Handler: TNotifyEvent);
  476. begin
  477. FOnFontChange := Handler;
  478. end;
  479. procedure TGDIBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
  480. begin
  481. if FOwner.Empty then
  482. Exit;
  483. if not FOwner.MeasuringMode then
  484. StretchBlt(Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
  485. DstRect.Bottom - DstRect.Top, hSrc, SrcRect.Left, SrcRect.Top,
  486. SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
  487. FOwner.Changed(DstRect);
  488. end;
  489. function TGDIBackend.CanvasAllocated: Boolean;
  490. begin
  491. Result := Assigned(FCanvas);
  492. end;
  493. function TGDIBackend.Empty: Boolean;
  494. begin
  495. Result := FBitmapHandle = 0;
  496. end;
  497. procedure TGDIBackend.FontChangedHandler(Sender: TObject);
  498. begin
  499. if FFontHandle <> 0 then
  500. begin
  501. if Handle <> 0 then SelectObject(Handle, StockFont);
  502. FFontHandle := 0;
  503. end;
  504. FontChanged;
  505. end;
  506. procedure TGDIBackend.CanvasChangedHandler(Sender: TObject);
  507. begin
  508. CanvasChanged;
  509. end;
  510. { IPaintSupport }
  511. procedure TGDIBackend.ImageNeeded;
  512. begin
  513. end;
  514. procedure TGDIBackend.CheckPixmap;
  515. begin
  516. end;
  517. procedure TGDIBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas);
  518. var
  519. i: Integer;
  520. CanvasHandle: HDC;
  521. BufferHandle: HDC;
  522. begin
  523. CanvasHandle := ACanvas.Handle;
  524. BufferHandle := ABuffer.Handle;
  525. for i := 0 to AInvalidRects.Count - 1 do
  526. with AInvalidRects[i]^ do
  527. BitBlt(CanvasHandle, Left, Top, Right - Left, Bottom - Top, BufferHandle, Left, Top, SRCCOPY);
  528. end;
  529. procedure TGDIBackend.DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas);
  530. begin
  531. BitBlt(ACanvas.Handle, AInvalidRect.Left, AInvalidRect.Top, AInvalidRect.Width, AInvalidRect.Height,
  532. ABuffer.Handle, AInvalidRect.Left, AInvalidRect.Top, SRCCOPY);
  533. end;
  534. { TGDIMMFBackend }
  535. constructor TGDIMMFBackend.Create(Owner: TBitmap32; IsTemporary: Boolean = True; const MapFileName: string = '');
  536. begin
  537. FMapFileName := MapFileName;
  538. FMapIsTemporary := IsTemporary;
  539. TMMFBackend.InitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  540. inherited Create(Owner);
  541. end;
  542. destructor TGDIMMFBackend.Destroy;
  543. begin
  544. TMMFBackend.DeinitializeFileMapping(FMapHandle, FMapFileHandle, FMapFileName);
  545. inherited;
  546. end;
  547. procedure TGDIMMFBackend.PrepareFileMapping(NewWidth, NewHeight: Integer);
  548. begin
  549. TMMFBackend.CreateFileMapping(FMapHandle, FMapFileHandle, FMapFileName, FMapIsTemporary, NewWidth, NewHeight);
  550. end;
  551. { TGDIMemoryBackend }
  552. constructor TGDIMemoryBackend.Create;
  553. begin
  554. inherited;
  555. FBitmapInfo := Default(TBitmapInfo);
  556. FBitmapInfo.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
  557. FBitmapInfo.bmiHeader.biPlanes := 1;
  558. FBitmapInfo.bmiHeader.biBitCount := 32;
  559. FBitmapInfo.bmiHeader.biCompression := BI_RGB;
  560. FBitmapInfo.bmiHeader.biXPelsPerMeter := 96;
  561. FBitmapInfo.bmiHeader.biYPelsPerMeter := 96;
  562. end;
  563. procedure TGDIMemoryBackend.InitializeSurface(NewWidth, NewHeight: Integer;
  564. ClearBuffer: Boolean);
  565. begin
  566. inherited;
  567. FBitmapInfo.bmiHeader.biWidth := NewWidth;
  568. FBitmapInfo.bmiHeader.biHeight := -NewHeight; // Bottom-up DIB
  569. end;
  570. procedure TGDIMemoryBackend.ImageNeeded;
  571. begin
  572. end;
  573. procedure TGDIMemoryBackend.CheckPixmap;
  574. begin
  575. end;
  576. procedure TGDIMemoryBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas);
  577. var
  578. i : Integer;
  579. begin
  580. for i := 0 to AInvalidRects.Count - 1 do
  581. DoPaintRect(ABuffer, AInvalidRects[i]^, ACanvas);
  582. end;
  583. procedure TGDIMemoryBackend.DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas);
  584. begin
  585. DoPaintRect(ABuffer, AInvalidRect, ACanvas);
  586. end;
  587. procedure TGDIMemoryBackend.DoPaintRect(ABuffer: TBitmap32; ARect: TRect; ACanvas: TCanvas);
  588. var
  589. Bitmap : HBITMAP;
  590. DeviceContext : HDC;
  591. Buffer : Pointer;
  592. OldObject : HGDIOBJ;
  593. begin
  594. if SetDIBitsToDevice(ACanvas.Handle, ARect.Left, ARect.Top, ARect.Right -
  595. ARect.Left, ARect.Bottom - ARect.Top, ARect.Left, ARect.Top, 0,
  596. ARect.Bottom - ARect.Top, ABuffer.Bits, FBitmapInfo, DIB_RGB_COLORS) <> 0 then
  597. exit;
  598. // create compatible device context
  599. DeviceContext := CreateCompatibleDC(ACanvas.Handle);
  600. if DeviceContext = 0 then
  601. exit;
  602. try
  603. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS, Buffer, 0, 0);
  604. if Bitmap = 0 then
  605. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  606. OldObject := SelectObject(DeviceContext, Bitmap);
  607. try
  608. Move(ABuffer.Bits^, Buffer^, FBitmapInfo.bmiHeader.biWidth * FBitmapInfo.bmiHeader.biHeight * SizeOf(SizeOf(TRGBQuad)));
  609. BitBlt(ACanvas.Handle, ARect.Left, ARect.Top, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, DeviceContext, 0, 0, SRCCOPY);
  610. finally
  611. if OldObject <> 0 then
  612. SelectObject(DeviceContext, OldObject);
  613. DeleteObject(Bitmap);
  614. end;
  615. finally
  616. DeleteDC(DeviceContext);
  617. end;
  618. end;
  619. procedure TGDIMemoryBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
  620. begin
  621. if FOwner.Empty then Exit;
  622. if not FOwner.MeasuringMode then
  623. raise EBackend.Create('Not supported!');
  624. FOwner.Changed(DstRect);
  625. end;
  626. procedure TGDIMemoryBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
  627. var
  628. Bitmap : HBITMAP;
  629. DeviceContext : HDC;
  630. Buffer : Pointer;
  631. OldObject : HGDIOBJ;
  632. begin
  633. if SetDIBitsToDevice(hDst, DstX, DstY, FOwner.Width, FOwner.Height, 0, 0, 0,
  634. FOwner.Height, FBits, FBitmapInfo, DIB_RGB_COLORS) <> 0 then
  635. exit;
  636. // create compatible device context
  637. DeviceContext := CreateCompatibleDC(hDst);
  638. if DeviceContext = 0 then
  639. exit;
  640. try
  641. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS, Buffer, 0, 0);
  642. if Bitmap = 0 then
  643. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  644. OldObject := SelectObject(DeviceContext, Bitmap);
  645. try
  646. Move(FBits^, Buffer^, FBitmapInfo.bmiHeader.biWidth * FBitmapInfo.bmiHeader.biHeight * SizeOf(TRGBQuad));
  647. BitBlt(hDst, DstX, DstY, FOwner.Width, FOwner.Height, DeviceContext, 0, 0, SRCCOPY);
  648. finally
  649. if OldObject <> 0 then
  650. SelectObject(DeviceContext, OldObject);
  651. DeleteObject(Bitmap);
  652. end;
  653. finally
  654. DeleteDC(DeviceContext);
  655. end;
  656. end;
  657. procedure TGDIMemoryBackend.DrawTo(hDst: HDC;
  658. const DstRect, SrcRect: TRect);
  659. var
  660. Bitmap : HBITMAP;
  661. DeviceContext : HDC;
  662. Buffer : Pointer;
  663. OldObject : HGDIOBJ;
  664. begin
  665. if SetDIBitsToDevice(hDst, DstRect.Left, DstRect.Top,
  666. DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, SrcRect.Left,
  667. SrcRect.Top, 0, SrcRect.Bottom - SrcRect.Top, FBits, FBitmapInfo,
  668. DIB_RGB_COLORS) <> 0 then
  669. exit;
  670. // create compatible device context
  671. DeviceContext := CreateCompatibleDC(hDst);
  672. if DeviceContext = 0 then
  673. raise EBackend.Create(RCStrCannotCreateCompatibleDC);
  674. try
  675. Bitmap := CreateDIBSection(DeviceContext, FBitmapInfo, DIB_RGB_COLORS, Buffer, 0, 0);
  676. if Bitmap = 0 then
  677. exit;
  678. OldObject := SelectObject(DeviceContext, Bitmap);
  679. try
  680. Move(FBits^, Buffer^, FBitmapInfo.bmiHeader.biWidth * FBitmapInfo.bmiHeader.biHeight * SizeOf(TRGBQuad));
  681. BitBlt(hDst, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, DeviceContext, 0, 0, SRCCOPY);
  682. finally
  683. if OldObject <> 0 then
  684. SelectObject(DeviceContext, OldObject);
  685. DeleteObject(Bitmap);
  686. end;
  687. finally
  688. DeleteDC(DeviceContext);
  689. end;
  690. end;
  691. function TGDIMemoryBackend.GetHandle: HDC;
  692. begin
  693. Result := 0;
  694. end;
  695. initialization
  696. StockFont := GetStockObject(SYSTEM_FONT);
  697. finalization
  698. end.