123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- unit GR32_Backends_LCL_Carbon;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Backend Extension for Graphics32
- *
- * The Initial Developer of the Original Code is
- * Felipe Monteiro de Carvalho <[email protected]>
- *
- * Portions created by the Initial Developer are Copyright (C) 2007-2012
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$include GR32.inc}
- uses
- { RTL and LCL }
- LCLIntf, LCLType, types, Controls, SysUtils, Classes, Graphics,
- { Carbon bindings }
- MacOSAll,
- { Carbon lcl interface }
- CarbonCanvas, CarbonPrivate,
- { Graphics 32 }
- GR32,
- GR32_Backends,
- GR32_Containers;
- const
- STR_GenericRGBProfilePath = '/System/Library/ColorSync/Profiles/Generic RGB Profile.icc';
- type
- { TLCLBackend }
- TLCLBackend = class(TCustomBackend,
- IPaintSupport, IDeviceContextSupport,
- ITextSupport, IFontSupport, ICanvasSupport)
- private
- FFont: TFont;
- FCanvas: TCanvas;
- FOnFontChange: TNotifyEvent;
- FOnCanvasChange: TNotifyEvent;
- { Carbon specific variables }
- Stride: Integer;
- FWidth, FHeight: Cardinal;
- FProfile: CMProfileRef;
- FColorSpace: CGColorSpaceRef;
- FContext: CGContextRef;
- FCanvasHandle: TCarbonDeviceContext;
- { Functions to easely generate carbon structures }
- function GetCarbonRect(Left, Top, Width, Height: Integer): MacOSAll.Rect;
- function GetCGRect(Left, Top, Width, Height: Integer): MacOSAll.CGRect; overload;
- function GetCGRect(SrcRect: TRect): MacOSAll.CGRect; overload;
- protected
- { BITS_GETTER }
- function GetBits: PColor32Array; override;
- procedure InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean); override;
- procedure FinalizeSurface; override;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure Changed; override;
- function Empty: Boolean; override;
- public
- { IPaintSupport }
- procedure ImageNeeded;
- procedure CheckPixmap;
- procedure DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas); overload;
- procedure DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas); overload;
- { IDeviceContextSupport }
- function GetHandle: HDC;
- procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
- procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
- procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
- property Handle: HDC read GetHandle;
- { ITextSupport }
- procedure Textout(X, Y: Integer; const Text: string); overload;
- procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: string); overload;
- procedure Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string); overload;
- function TextExtent(const Text: string): TSize;
- { IFontSupport }
- function GetOnFontChange: TNotifyEvent;
- procedure SetOnFontChange(Handler: TNotifyEvent);
- function GetFont: TFont;
- procedure SetFont(const Font: TFont);
- procedure UpdateFont;
- property Font: TFont read GetFont write SetFont;
- property OnFontChange: TNotifyEvent read FOnFontChange write FOnFontChange;
- { IInteroperabilitySupport }
- function CopyFrom(Graphic: TGraphic): Boolean; overload;
- { ICanvasSupport }
- function GetCanvasChange: TNotifyEvent;
- procedure SetCanvasChange(Handler: TNotifyEvent);
- function GetCanvas: TCanvas;
- procedure DeleteCanvas;
- function CanvasAllocated: Boolean;
- property Canvas: TCanvas read GetCanvas;
- property OnCanvasChange: TNotifyEvent read GetCanvasChange write SetCanvasChange;
- end;
- implementation
- uses
- GR32_LowLevel;
- var
- StockFont: TFont;
- { TLCLBackend }
- function TLCLBackend.GetCarbonRect(Left, Top, Width, Height: Integer): MacOSAll.Rect;
- begin
- Result.Left := Left;
- Result.Top := Top;
- Result.Right := Left + Width;
- Result.Bottom := Top + Height;
- end;
- function TLCLBackend.GetCGRect(Left, Top, Width, Height: Integer): MacOSAll.CGRect;
- begin
- Result.Origin.X := Left;
- Result.Origin.Y := Top;
- Result.Size.Width := Width;
- Result.Size.Height := Height;
- end;
- function TLCLBackend.GetCGRect(SrcRect: TRect): MacOSAll.CGRect;
- begin
- Result.Origin.X := SrcRect.Left;
- Result.Origin.Y := SrcRect.Top;
- Result.Size.Width := SrcRect.Right - SrcRect.Left;
- Result.Size.Height := SrcRect.Bottom - SrcRect.Top;
- end;
- constructor TLCLBackend.Create;
- var
- loc: CMProfileLocation;
- status: OSStatus;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Create]', ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- inherited;
- { Creates a standard font }
- FFont := TFont.Create;
- { Creates a generic color profile }
- loc.locType := cmPathBasedProfile;
- loc.u.pathLoc.path := STR_GenericRGBProfilePath;
-
- status := CMOpenProfile(FProfile, loc);
-
- if status <> noErr then raise Exception.Create('Couldn''t create the generic profile');
-
- { Creates a generic color space }
-
- FColorSpace := CGColorSpaceCreateWithPlatformColorSpace(FProfile);
-
- if FColorSpace = nil then raise Exception.Create('Couldn''t create the generic RGB color space');
- end;
- destructor TLCLBackend.Destroy;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Destroy]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- { Deallocates the standard font }
- FFont.Free;
- { Closes the profile }
- CMCloseProfile(FProfile);
-
- inherited;
- end;
- function TLCLBackend.GetBits: PColor32Array;
- begin
- Result := FBits;
- end;
- procedure TLCLBackend.InitializeSurface(NewWidth, NewHeight: Integer; ClearBuffer: Boolean);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.InitializeSurface] BEGIN',
- ' Self: ', IntToHex(PtrUInt(Self), 8),
- ' NewWidth: ', NewWidth,
- ' NewHeight: ', NewHeight
- );
- {$ENDIF}
- { We allocate our own memory for the image }
- Stride := NewWidth * 4;
- FBits := System.GetMem(NewHeight * Stride);
- if FBits = nil then
- raise Exception.Create('[TLCLBackend.InitializeSurface] ERROR FBits = nil');
- { Creates a device context for our raw image area }
- FContext := CGBitmapContextCreate(FBits,
- NewWidth, NewHeight, 8, Stride, FColorSpace,
- kCGImageAlphaNoneSkipFirst or kCGBitmapByteOrder32Little);
- if FContext = nil then
- raise Exception.Create('[TLCLBackend.InitializeSurface] ERROR FContext = nil');
- { flip and offset CTM to upper left corner }
- CGContextTranslateCTM(FContext, 0, NewHeight);
- CGContextScaleCTM(FContext, 1, -1);
- FWidth := NewWidth;
- FHeight := NewHeight;
- { clear the image }
- if ClearBuffer then
- FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.InitializeSurface] END');
- {$ENDIF}
- end;
- procedure TLCLBackend.FinalizeSurface;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.FinalizeSurface]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- if Assigned(FBits) then System.FreeMem(FBits);
- FBits := nil;
-
- if Assigned(FContext) then CGContextRelease(FContext);
- FContext := nil;
- end;
- procedure TLCLBackend.Changed;
- begin
- inherited;
- end;
- function TLCLBackend.Empty: Boolean;
- begin
- Result := (FContext = nil) or (FBits = nil);
- end;
- { IPaintSupport }
- procedure TLCLBackend.ImageNeeded;
- begin
- end;
- procedure TLCLBackend.CheckPixmap;
- begin
- end;
- procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; AInvalidRects: TRectList; ACanvas: TCanvas);
- var
- ImageRef: CGImageRef;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.DoPaint]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- { CGContextDrawImage is also possible, but it doesn't flip the image }
- ImageRef := CGBitmapContextCreateImage(FContext);
- try
- HIViewDrawCGImage(
- TCarbonDeviceContext(ACanvas.Handle).CGContext,
- GetCGRect(0, 0, FWidth, FHeight), imageRef);
- finally
- if Assigned(ImageRef) then
- CGImageRelease(ImageRef);
- end;
- end;
- procedure TLCLBackend.DoPaint(ABuffer: TBitmap32; const AInvalidRect: TRect; ACanvas: TCanvas);
- begin
- DoPaint(ABuffer, nil, ACanvas);
- end;
- { IDeviceContextSupport }
- function TLCLBackend.GetHandle: HDC;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetHandle]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- if not Assigned(FCanvas) then GetCanvas;
- Result := FCanvas.Handle;
- end;
- procedure TLCLBackend.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
- var
- original, subsection: CGImageRef;
- CGDstRect, CGSrcRect: CGRect;
- ExternalContext: CGContextRef;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Draw]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- // Gets the external context
- if (hSrc = 0) then Exit;
- ExternalContext := TCarbonDeviceContext(hSrc).CGContext;
- // Converts the rectangles to CoreGraphics rectangles
- CGDstRect := GetCGRect(DstRect);
- CGSrcRect := GetCGRect(SrcRect);
- // Gets an image handle that represents the subsection
- original := CGBitmapContextCreateImage(ExternalContext);
- subsection := CGImageCreateWithImageInRect(original, CGSrcRect);
- CGImageRelease(original);
- { We need to make adjustments to the CTM so the painting is done correctly }
- CGContextSaveGState(FContext);
- try
- CGContextTranslateCTM(FContext, 0, FOwner.Height);
- CGContextScaleCTM(FContext, 1, -1);
- CGContextTranslateCTM(FContext, 0, -CGDstRect.origin.y);
- CGDstRect.origin.y := 0;
- { Draw the subsection }
- CGContextDrawImage(FContext, CGDstRect, subsection);
- finally
- { reset the CTM to the old values }
- CGContextRestoreGState(FContext);
- end;
- // Release the subsection
- CGImageRelease(subsection);
- end;
- procedure TLCLBackend.DrawTo(hDst: HDC; DstX, DstY: Integer);
- var
- DstRect, SrcRect: TRect;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.DrawTo]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
-
- DstRect.Left := DstX;
- DstRect.Top := DstY;
- DstRect.Right := FOwner.Width + DstX;
- DstRect.Bottom := FOwner.Height + DstY;
- SrcRect.Left := 0;
- SrcRect.Top := 0;
- SrcRect.Right := FOwner.Width;
- SrcRect.Bottom := FOwner.Height;
- DrawTo(hDst, DstRect, SrcRect);
- end;
- procedure TLCLBackend.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
- var
- original, subsection: CGImageRef;
- CGDstRect, CGSrcRect: CGRect;
- ExternalContext: CGContextRef;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.DrawTo with rects]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- // Gets the external context
- if (hDst = 0) then Exit;
- ExternalContext := TCarbonDeviceContext(hDst).CGContext;
- // Converts the rectangles to CoreGraphics rectangles
- CGDstRect := GetCGRect(DstRect);
- CGSrcRect := GetCGRect(SrcRect);
- // Gets an image handle that represents the subsection
- original := CGBitmapContextCreateImage(FContext);
- subsection := CGImageCreateWithImageInRect(original, CGSrcRect);
- CGImageRelease(original);
-
- { We need to make adjustments to the CTM so the painting is done correctly }
- CGContextSaveGState(ExternalContext);
- try
- CGContextTranslateCTM(ExternalContext, 0, FOwner.Height);
- CGContextScaleCTM(ExternalContext, 1, -1);
- CGContextTranslateCTM(ExternalContext, 0, -CGDstRect.origin.y);
- CGDstRect.origin.y := 0;
- { Draw the subsection }
- CGContextDrawImage(ExternalContext, CGDstRect, subsection);
- finally
- { reset the CTM to the old values }
- CGContextRestoreGState(ExternalContext);
- end;
-
- // Release the subsection
- CGImageRelease(subsection);
- end;
- { ITextSupport }
- procedure TLCLBackend.Textout(X, Y: Integer; const Text: string);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Textout]', ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- if not Assigned(FCanvas) then GetCanvas;
- UpdateFont;
- if not FOwner.MeasuringMode then
- FCanvas.TextOut(X, Y, Text);
- FOwner.Changed;
- end;
- procedure TLCLBackend.Textout(X, Y: Integer; const ClipRect: TRect; const Text: string);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Textout with ClipRect]', ' Self: ',
- IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
-
- if not Assigned(FCanvas) then GetCanvas;
- UpdateFont;
- LCLIntf.ExtTextOut(FCanvas.Handle, X, Y, ETO_CLIPPED, @ClipRect, PChar(Text),
- Length(Text), nil);
- end;
- procedure TLCLBackend.Textout(var DstRect: TRect; const Flags: Cardinal; const Text: string);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.Textout with Flags]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
-
- if not Assigned(FCanvas) then GetCanvas;
- UpdateFont;
- LCLIntf.DrawText(FCanvas.Handle, PChar(Text), Length(Text), DstRect, Flags);
- end;
- function TLCLBackend.TextExtent(const Text: string): TSize;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.TextExtent]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- if not Assigned(FCanvas) then GetCanvas;
- UpdateFont;
- Result := FCanvas.TextExtent(Text);
- end;
- { IFontSupport }
- function TLCLBackend.GetOnFontChange: TNotifyEvent;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetOnFontChange]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- Result := FFont.OnChange;
- end;
- procedure TLCLBackend.SetOnFontChange(Handler: TNotifyEvent);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.SetOnFontChange]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- FFont.OnChange := Handler;
- end;
- function TLCLBackend.GetFont: TFont;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetFont]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- Result := FFont;
- end;
- procedure TLCLBackend.SetFont(const Font: TFont);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.SetFont]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- FFont.Assign(Font);
- end;
- procedure TLCLBackend.UpdateFont;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.UpdateFont]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- FFont.OnChange := FOnFontChange;
- if Assigned(FCanvas) then FCanvas.Font := FFont;
- end;
- { IInteroperabilitySupport }
- type
- TGraphicAccess = class(TGraphic);
- function TLCLBackend.CopyFrom(Graphic: TGraphic): Boolean;
- begin
- TGraphicAccess(Graphic).Draw(Canvas, MakeRect(0, 0, FCanvas.Width, FCanvas.Height));
- end;
- { ICanvasSupport }
- function TLCLBackend.GetCanvasChange: TNotifyEvent;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetCanvasChange]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- Result := FOnCanvasChange;
- end;
- procedure TLCLBackend.SetCanvasChange(Handler: TNotifyEvent);
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.SetCanvasChange]',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- FOnCanvasChange := Handler;
- end;
- function TLCLBackend.GetCanvas: TCanvas;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetCanvas] BEGIN',
- ' Self: ', IntToHex(PtrUInt(Self), 8));
- {$ENDIF}
- if FCanvas = nil then
- begin
- FCanvas := TCanvas.Create;
- FCanvasHandle := TCarbonDeviceContext.Create;
- FCanvasHandle.CGContext := FContext;
- FCanvas.Handle := HDC(FCanvasHandle);
- FCanvas.OnChange := FOnCanvasChange;
- FCanvas.Font := FFont;
- end;
-
- Result := FCanvas;
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.GetCanvas] END');
- {$ENDIF}
- end;
- procedure TLCLBackend.DeleteCanvas;
- begin
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.DeleteCanvas]',
- ' Self: ', IntToHex(PtrUInt(Self), 8),
- ' FCanvas: ', PtrUInt(FCanvas));
- {$ENDIF}
- if Assigned(FCanvas) then
- begin
- FCanvas.Handle := 0;
- FCanvas.Free;
- FCanvas := nil;
- end;
- end;
- function TLCLBackend.CanvasAllocated: Boolean;
- begin
- Result := (FCanvas <> nil);
- {$IFDEF VerboseGR32Carbon}
- WriteLn('[TLCLBackend.CanvasAllocated]',
- ' Self: ', IntToHex(PtrUInt(Self), 8),
- ' FCanvas: ', PtrUInt(FCanvas));
- {$ENDIF}
- end;
- initialization
- StockFont := TFont.Create;
- finalization
- StockFont.Free;
- end.
|