GR32_Backends_LCL_Gtk.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. unit GR32_Backends_LCL_Gtk;
  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. * Anders Melander <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2007-2024
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. {$DEFINE VerboseGR32GTK}
  34. uses
  35. LCLIntf, LCLType,
  36. Types, Controls, SysUtils, Classes,
  37. {$IFDEF LCLGtk2}
  38. gdk2, gdk2pixbuf, glib2, gtk2Def, gtk2,
  39. {$ELSE}
  40. gdk, gdkpixbuf, glib, gtkdef,
  41. {$ENDIF}
  42. Graphics, GraphType, FPImage, IntfGraphics,
  43. GR32,
  44. GR32_Backends,
  45. GR32_Containers;
  46. type
  47. { TLCLBackend }
  48. TLCLBackend = class(TCustomBackend,
  49. IPaintSupport,
  50. ITextSupport,
  51. IFontSupport,
  52. ICanvasSupport,
  53. IDeviceContextSupport,
  54. IInteroperabilitySupport,
  55. IUpdateRectSupport
  56. )
  57. private
  58. FFont: TFont;
  59. FOnFontChange: TNotifyEvent;
  60. FOnCanvasChange: TNotifyEvent;
  61. FWidth, FHeight: Cardinal;
  62. FRawImage: TRawImage;
  63. FBitmap: TBitmap;
  64. FPixmapDirty: boolean;
  65. FCanvasDirty: boolean;
  66. private
  67. procedure CanvasChangedHandler(Sender: TObject);
  68. procedure CanvasChanged;
  69. procedure CopyPixmapToCanvas;
  70. procedure CopyCanvasToPixmap;
  71. procedure NeedBits; {$IFDEF USEINLINING} inline; {$ENDIF}
  72. procedure NeedCanvas; {$IFDEF USEINLINING} inline; {$ENDIF}
  73. protected
  74. {$IFDEF BITS_GETTER}
  75. function GetBits: PColor32Array; override;
  76. {$ELSE BITS_GETTER}
  77. {$MESSAGE FATAL LCL GTK backend requires that BITS_GETTER is defined}
  78. {$ENDIF BITS_GETTER}
  79. procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
  80. procedure FinalizeSurface; override;
  81. protected
  82. // IPaintSupport
  83. procedure ImageNeeded;
  84. procedure CheckPixmap;
  85. procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas); overload;
  86. procedure DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas); overload;
  87. protected
  88. // IDeviceContextSupport
  89. function GetHandle: HDC;
  90. procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
  91. procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
  92. procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
  93. protected
  94. // ITextSupport
  95. procedure Textout(X, Y: Integer; const Text: string); overload;
  96. procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: string); overload;
  97. procedure Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string); overload;
  98. function TextExtent(const Text: string): TSize;
  99. protected
  100. // IFontSupport
  101. function GetOnFontChange: TNotifyEvent;
  102. procedure SetOnFontChange(Handler: TNotifyEvent);
  103. function GetFont: TFont;
  104. procedure SetFont(const AFont: TFont);
  105. procedure UpdateFont;
  106. property Font: TFont read GetFont;
  107. protected
  108. // IInteroperabilitySupport
  109. function CopyFrom(ImageBitmap: TFPImageBitmap): Boolean; overload;
  110. function CopyFrom(Graphic: TGraphic): Boolean; overload;
  111. protected
  112. // ICanvasSupport
  113. function GetCanvasChange: TNotifyEvent;
  114. procedure SetCanvasChange(Handler: TNotifyEvent);
  115. function GetCanvas: TCanvas;
  116. function CanvasAllocated: Boolean;
  117. procedure DeleteCanvas;
  118. protected
  119. { IUpdateRectSupport }
  120. procedure InvalidateRect(AControl: TWinControl; const ARect: TRect);
  121. procedure GetUpdateRects(AControl: TWinControl; AUpdateRects: TRectList; AReservedCapacity: integer; var AFullUpdate: boolean);
  122. protected
  123. property Canvas: TCanvas read GetCanvas;
  124. public
  125. constructor Create; override;
  126. destructor Destroy; override;
  127. procedure Changed; override;
  128. function Empty: Boolean; override;
  129. end;
  130. implementation
  131. uses
  132. Math,
  133. GR32_LowLevel;
  134. { TLCLBackend }
  135. constructor TLCLBackend.Create;
  136. begin
  137. inherited;
  138. end;
  139. destructor TLCLBackend.Destroy;
  140. begin
  141. FFont.Free;
  142. FBitmap.Free;
  143. inherited;
  144. end;
  145. procedure TLCLBackend.NeedBits;
  146. begin
  147. // If canvas was modified, copy it back to the pixmap
  148. if (FCanvasDirty) then
  149. CopyCanvasToPixmap;
  150. end;
  151. procedure TLCLBackend.NeedCanvas;
  152. begin
  153. if (FBitmap = nil) then
  154. begin
  155. FBitmap := TBitmap.Create;
  156. FBitmap.Canvas.Brush.Style := bsClear; // Otherwise text is drawn opaque
  157. FBitmap.Canvas.OnChange := CanvasChangedHandler;
  158. FBitmap.LoadFromRawImage(FRawImage, False);
  159. FPixmapDirty := False;
  160. FCanvasDirty := False;
  161. end;
  162. // If pixmap was modified ensure that canvas is up to date
  163. if (FPixmapDirty) then
  164. CopyPixmapToCanvas;
  165. end;
  166. procedure TLCLBackend.CopyCanvasToPixmap;
  167. var
  168. PixBuf: PGdkPixbuf;
  169. P: TPoint;
  170. SourceBits: pointer;
  171. begin
  172. // Allocate a new pixbuf, 8 bits per channel with alpha.
  173. PixBuf := gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, FWidth, FHeight);
  174. try
  175. P := TGtkDeviceContext(Canvas.Handle).Offset;
  176. // Fill the pixbuf with the canvas pixel data
  177. if (gdk_pixbuf_get_from_drawable(PixBuf,
  178. TGtkDeviceContext(Canvas.Handle).Drawable, nil,
  179. P.X,P.Y, 0,0, FWidth, FHeight) = nil) then
  180. raise Exception.Create('[TLCLBackend.CopyCanvasToPixmap] gdk_pixbuf_get_from_drawable failed');
  181. // Note: we cant directly assign data pointer to FBits here,
  182. // because the pointer will be soon disposed (see 'finally' below).
  183. // Instead, we should do copy the pixels (pointer content) to FBits to keep it accesible later.
  184. // Get a pointer to the pixbuf pixel data
  185. SourceBits := gdk_pixbuf_get_pixels(PixBuf);
  186. // Copy data (pointer content) from pixbuf to pixmap
  187. MoveLongword(SourceBits^, FBits^, FWidth*FHeight);
  188. finally
  189. g_object_unref(PixBuf);
  190. end;
  191. FPixmapDirty := False;
  192. FCanvasDirty := False;
  193. end;
  194. procedure TLCLBackend.CopyPixmapToCanvas;
  195. var
  196. P: TPoint;
  197. begin
  198. P := TGtkDeviceContext(FBitmap.Canvas.Handle).Offset;
  199. // Draw the pixbuf data onto the canvas.
  200. gdk_draw_rgb_32_image(TGtkDeviceContext(FBitmap.Canvas.Handle).Drawable,
  201. TGtkDeviceContext(FBitmap.Canvas.Handle).GC, P.X, P.Y, FWidth, FHeight,
  202. GDK_RGB_DITHER_NONE, pguchar(FBits), FWidth * SizeOf(TColor32));
  203. FPixmapDirty := False;
  204. FCanvasDirty := False;
  205. end;
  206. {$IFDEF BITS_GETTER}
  207. function TLCLBackend.GetBits: PColor32Array;
  208. begin
  209. NeedBits;
  210. Result := FBits;
  211. // Since caller now has direct access to the pixmap, assume it will be modified
  212. FPixmapDirty := True;
  213. end;
  214. {$ENDIF}
  215. procedure TLCLBackend.CanvasChangedHandler(Sender: TObject);
  216. begin
  217. CanvasChanged;
  218. end;
  219. procedure TLCLBackend.CanvasChanged;
  220. begin
  221. FCanvasDirty := True;
  222. if Assigned(FOnCanvasChange) then
  223. FOnCanvasChange(Self);
  224. end;
  225. procedure TLCLBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
  226. begin
  227. { We allocate our own memory for the image }
  228. FRawImage.Init;
  229. {$ifdef RGBA_FORMAT}
  230. FRawImage.Description.Init_BPP32_R8G8B8A8_BIO_TTB(NewWidth, NewHeight);
  231. {$else RGBA_FORMAT}
  232. FRawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(NewWidth, NewHeight);
  233. {$endif RGBA_FORMAT}
  234. FRawImage.CreateData(ClearBuffer);
  235. FBits := PColor32Array(FRawImage.Data);
  236. if (FBits = nil) then
  237. raise Exception.Create('[TLCLBackend.InitializeSurface] FBits = nil');
  238. FWidth := NewWidth;
  239. FHeight := NewHeight;
  240. FPixmapDirty := True;
  241. end;
  242. procedure TLCLBackend.FinalizeSurface;
  243. begin
  244. if (FBits <> nil) then
  245. begin
  246. FRawImage.FreeData;
  247. FBits := nil;
  248. FreeAndNil(FBitmap);
  249. end;
  250. end;
  251. procedure TLCLBackend.Changed;
  252. begin
  253. inherited;
  254. end;
  255. function TLCLBackend.Empty: Boolean;
  256. begin
  257. Result := (FBits = nil);
  258. end;
  259. { IPaintSupport }
  260. procedure TLCLBackend.ImageNeeded;
  261. begin
  262. // empty by purpose
  263. end;
  264. procedure TLCLBackend.CheckPixmap;
  265. begin
  266. // empty by purpose
  267. end;
  268. procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas);
  269. var
  270. P: TPoint;
  271. begin
  272. P := TGtkDeviceContext(ACanvas.Handle).Offset;
  273. gdk_draw_rgb_32_image(TGtkDeviceContext(ACanvas.Handle).Drawable,
  274. TGtkDeviceContext(ACanvas.Handle).GC, P.X, P.Y,
  275. ABuffer.Width, ABuffer.Height,
  276. GDK_RGB_DITHER_NONE, pguchar(ABuffer.Bits), ABuffer.Width * SizeOf(TColor32)
  277. );
  278. end;
  279. procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas);
  280. begin
  281. DoPaint(ABuffer, nil, ACanvas);
  282. end;
  283. { IDeviceContextSupport }
  284. function TLCLBackend.GetHandle: HDC;
  285. begin
  286. Result := Canvas.Handle;
  287. end;
  288. procedure TLCLBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
  289. begin
  290. NeedCanvas;
  291. StretchMaskBlt(FBitmap.Canvas.Handle, DstRect.Left, DstRect.Top,
  292. DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
  293. hSrc, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left,
  294. SrcRect.Bottom - SrcRect.Top, 0, 0, 0, FBitmap.Canvas.CopyMode);
  295. end;
  296. procedure TLCLBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
  297. var
  298. P: TPoint;
  299. begin
  300. NeedBits;
  301. P := TGtkDeviceContext(hDst).Offset;
  302. Inc(DstX, P.X);
  303. Inc(DstY, P.Y);
  304. gdk_draw_rgb_32_image(TGtkDeviceContext(hDst).Drawable,
  305. TGtkDeviceContext(hDst).GC, DstX, DstY, FWidth, FHeight,
  306. GDK_RGB_DITHER_NONE, PGuChar(FBits), FWidth * SizeOf(TColor32)
  307. );
  308. end;
  309. procedure TLCLBackend.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
  310. var
  311. P: TPoint;
  312. DR: TRect;
  313. begin
  314. NeedBits;
  315. P := TGtkDeviceContext(hDst).Offset;
  316. DR := DstRect;
  317. Inc(DR.Left , P.X);
  318. Inc(DR.Right, P.X);
  319. gdk_draw_rgb_32_image(TGtkDeviceContext(hDst).Drawable,
  320. TGtkDeviceContext(hDst).GC, DR.Left, DR.Top, SrcRect.Right - SrcRect.Left,
  321. SrcRect.Bottom - SrcRect.Top, GDK_RGB_DITHER_NONE, PGuChar(FBits),
  322. FWidth * SizeOf(TColor32)
  323. );
  324. end;
  325. { ITextSupport }
  326. procedure TLCLBackend.Textout(X, Y: Integer; const Text: string);
  327. var
  328. Extent: TSize;
  329. ChangeRect: TRect;
  330. begin
  331. if Empty then
  332. Exit;
  333. UpdateFont;
  334. if (not FOwner.MeasuringMode) then
  335. begin
  336. if FOwner.Clipping then
  337. begin
  338. LCLIntf.ExtTextOut(Canvas.Handle, X, Y, ETO_CLIPPED, @FOwner.ClipRect, PChar(Text), Length(Text), nil);
  339. CanvasChanged;
  340. end else
  341. Canvas.TextOut(X, Y, Text);
  342. end;
  343. Extent := TextExtent(Text);
  344. ChangeRect := MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1);
  345. if FOwner.Clipping then
  346. ChangeRect.Intersect(FOwner.ClipRect);
  347. FOwner.Changed(ChangeRect);
  348. end;
  349. procedure TLCLBackend.Textout(X, Y: Integer; const ClipRect: TRect; const Text: string);
  350. var
  351. Extent: TSize;
  352. ActualClipRect: TRect;
  353. ChangeRect: TRect;
  354. begin
  355. if Empty then
  356. Exit;
  357. UpdateFont;
  358. ActualClipRect := ClipRect;
  359. if FOwner.Clipping then
  360. ActualClipRect.Intersect(FOwner.ClipRect);
  361. if (not FOwner.MeasuringMode) then
  362. begin
  363. LCLIntf.ExtTextOut(Canvas.Handle, X, Y, ETO_CLIPPED, @ActualClipRect, PChar(Text), Length(Text), nil);
  364. CanvasChanged;
  365. end;
  366. Extent := TextExtent(Text);
  367. ChangeRect := MakeRect(X, Y, X + Extent.cx + 1, Y + Extent.cy + 1);
  368. ChangeRect.Intersect(ActualClipRect);
  369. FOwner.Changed(ChangeRect);
  370. end;
  371. procedure TLCLBackend.Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string);
  372. var
  373. ChangeRect: TRect;
  374. TextCopy: string;
  375. begin
  376. if Empty then
  377. Exit;
  378. UpdateFont;
  379. if (not FOwner.MeasuringMode) then
  380. begin
  381. TextCopy := Text;
  382. if (Flags and DT_MODIFYSTRING <> 0) then
  383. UniqueString(TextCopy); // string must be writable
  384. LCLIntf.DrawText(Canvas.Handle, PChar(TextCopy), Length(TextCopy), DstRect, Flags);
  385. CanvasChanged;
  386. end else
  387. LCLIntf.DrawText(Canvas.Handle, PChar(TextCopy), Length(TextCopy), DstRect, (Flags or DT_CALCRECT) and (not DT_MODIFYSTRING));
  388. ChangeRect := DstRect;
  389. if FOwner.Clipping then
  390. ChangeRect.Intersect(FOwner.ClipRect);
  391. FOwner.Changed(ChangeRect);
  392. end;
  393. function TLCLBackend.TextExtent(const Text: string): TSize;
  394. begin
  395. Result.cx := 0;
  396. Result.cy := 0;
  397. UpdateFont;
  398. Result := Canvas.TextExtent(Text);
  399. end;
  400. { IFontSupport }
  401. function TLCLBackend.GetOnFontChange: TNotifyEvent;
  402. begin
  403. Result := Font.OnChange;
  404. end;
  405. procedure TLCLBackend.SetOnFontChange(Handler: TNotifyEvent);
  406. begin
  407. Font.OnChange := Handler;
  408. end;
  409. function TLCLBackend.GetFont: TFont;
  410. begin
  411. if (FFont = nil) then
  412. FFont := TFont.Create;
  413. Result := FFont;
  414. end;
  415. procedure TLCLBackend.SetFont(const AFont: TFont);
  416. begin
  417. Font.Assign(AFont);
  418. end;
  419. procedure TLCLBackend.UpdateFont;
  420. begin
  421. Font.OnChange := FOnFontChange;
  422. Canvas.Font := FFont;
  423. end;
  424. { IUpdateRectSupport }
  425. procedure TLCLBackend.InvalidateRect(AControl: TWinControl; const ARect: TRect);
  426. var
  427. Widget: PGtkWidget;
  428. UpdateRect: TGdkRectangle;
  429. begin
  430. // https://lazka.github.io/pgi-docs/Gdk-3.0/classes/Window.html#Gdk.Window.invalidate_rect
  431. // https://developer-old.gnome.org/pygtk/stable/class-gdkwindow.html#method-gdkwindow--invalidate-rect
  432. // procedure gdk_window_invalidate_rect(window:PGdkWindow; rect:PGdkRectangle; invalidate_children:gboolean); cdecl; external gdklib;
  433. Widget := PGtkWidget(AControl.Handle);
  434. UpdateRect.x := ARect.Left;
  435. UpdateRect.y := ARect.Top;
  436. UpdateRect.Width := ARect.Right-ARect.Left;
  437. UpdateRect.Height := ARect.Bottom-ARect.Top;
  438. gdk_window_invalidate_rect(Widget.window, @UpdateRect, False);
  439. end;
  440. procedure TLCLBackend.GetUpdateRects(AControl: TWinControl; AUpdateRects: TRectList; AReservedCapacity: integer;
  441. var AFullUpdate: boolean);
  442. var
  443. Widget: PGtkWidget;
  444. UpdateRegion: PGdkRegion;
  445. UpdateRects: PGdkRectangle;
  446. UpdateRect: PGdkRectangle;
  447. Count: integer;
  448. r: TRect;
  449. i: integer;
  450. begin
  451. // TODO : How do we get the update rect with GTK?
  452. // TGdkWindow.get_update_area ?
  453. // https://developer-old.gnome.org/pygtk/stable/class-gdkwindow.html#method-gdkwindow--get-update-area
  454. // function gdk_window_get_update_area(window:PGdkWindow):PGdkRegion; cdecl; external gdklib;
  455. Widget := PGtkWidget(AControl.Handle);
  456. UpdateRegion := gdk_window_get_update_area(Widget.window);
  457. if (UpdateRegion = PGdkRegion(GDK_NONE)) then
  458. exit;
  459. try
  460. if (gdk_region_empty(UpdateRegion)) then
  461. exit;
  462. gdk_region_get_rectangles(UpdateRegion, UpdateRects, @Count);
  463. try
  464. if (Count = 0) then
  465. exit;
  466. // Final count is known so set capacity to avoid reallocation
  467. AUpdateRects.Capacity := Math.Max(AUpdateRects.Capacity, AUpdateRects.Count + AReservedCapacity + Count);
  468. UpdateRect := UpdateRects;
  469. for i := 0 to Count-1 do
  470. begin
  471. r := MakeRect(UpdateRect.x, UpdateRect.y, UpdateRect.x+UpdateRect.Width, UpdateRect.y+UpdateRect.Height);
  472. AUpdateRects.Add(r);
  473. Inc(UpdateRect);
  474. end;
  475. finally
  476. g_free(UpdateRects)
  477. end;
  478. finally
  479. gdk_region_destroy(UpdateRegion);
  480. end;
  481. end;
  482. { IInteroperabilitySupport }
  483. type
  484. TGraphicAccess = class(TGraphic);
  485. function TLCLBackend.CopyFrom(ImageBitmap: TFPImageBitmap): Boolean;
  486. var
  487. Src: TLazIntfImage;
  488. X, Y: Integer;
  489. SrcLine: PCardinalArray;
  490. DestLine: PByte;
  491. begin
  492. NeedBits; // Ensure that pixmap is up to date
  493. Src := ImageBitmap.CreateIntfImage;
  494. try
  495. if ImageBitmap.Transparent then
  496. begin
  497. for Y := 0 to Src.Height - 1 do
  498. begin
  499. SrcLine := Src.GetDataLineStart(Y);
  500. DestLine := FRawImage.GetLineStart(Y);
  501. for X := 0 to Src.Width - 1 do
  502. begin
  503. DestLine^ := BlueComponent(SrcLine^[X]);
  504. Inc(DestLine);
  505. DestLine^ := GreenComponent(SrcLine^[X]);
  506. Inc(DestLine);
  507. DestLine^ := RedComponent(SrcLine^[X]);
  508. Inc(DestLine);
  509. DestLine^ := AlphaComponent(SrcLine^[X]);
  510. Inc(DestLine);
  511. end;
  512. end;
  513. end
  514. else
  515. begin
  516. for Y := 0 to Src.Height - 1 do
  517. begin
  518. SrcLine := Src.GetDataLineStart(Y);
  519. DestLine := FRawImage.GetLineStart(Y);
  520. for X := 0 to Src.Width - 1 do
  521. begin
  522. DestLine^ := BlueComponent(SrcLine^[X]);
  523. Inc(DestLine);
  524. DestLine^ := GreenComponent(SrcLine^[X]);
  525. Inc(DestLine);
  526. DestLine^ := RedComponent(SrcLine^[X]);
  527. Inc(DestLine);
  528. DestLine^ := $FF;
  529. Inc(DestLine);
  530. end;
  531. end;
  532. end;
  533. finally
  534. Src.Free;
  535. end;
  536. Result := True;
  537. end;
  538. function TLCLBackend.CopyFrom(Graphic: TGraphic): Boolean;
  539. begin
  540. Result := (Graphic is TFPImageBitmap) and CopyFrom(TFPImageBitmap(Graphic));
  541. if not Result then
  542. begin
  543. NeedCanvas;
  544. TGraphicAccess(Graphic).Draw(FBitmap.Canvas, MakeRect(0, 0, FBitmap.Canvas.Width, FBitmap.Canvas.Height));
  545. Result := True;
  546. end;
  547. end;
  548. { ICanvasSupport }
  549. function TLCLBackend.GetCanvasChange: TNotifyEvent;
  550. begin
  551. Result := FOnCanvasChange;
  552. end;
  553. procedure TLCLBackend.SetCanvasChange(Handler: TNotifyEvent);
  554. begin
  555. FOnCanvasChange := Handler;
  556. end;
  557. function TLCLBackend.GetCanvas: TCanvas;
  558. begin
  559. NeedCanvas;
  560. Result := FBitmap.Canvas;
  561. end;
  562. function TLCLBackend.CanvasAllocated: Boolean;
  563. begin
  564. result := GetCanvas() <> nil;
  565. end;
  566. procedure TLCLBackend.DeleteCanvas;
  567. begin
  568. end;
  569. end.