lazarus/lcl/interfaces/cocoa/cocoaobject.inc
2020-12-15 06:57:35 +00:00

847 lines
24 KiB
PHP

{%MainUnit cocoaint.pas}
{******************************************************************************
All utility method implementations of the TCocoaWidgetSet class are here.
******************************************************************************
Implementation
******************************************************************************
*****************************************************************************
This file is part of the Lazarus Component Library (LCL)
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
}
{ TCocoaWidgetSet }
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppInit
Params: ScreenInfo
Initialize Cocoa Widget Set
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
var
lDict: NSDictionary;
begin
{$IFDEF VerboseObject}
DebugLn('TCocoaWidgetSet.AppInit');
{$ENDIF}
InternalInit;
WakeMainThread := @OnWakeMainThread;
ScreenInfo.PixelsPerInchX := CocoaBasePPI;
ScreenInfo.PixelsPerInchY := CocoaBasePPI;
{ Creates the application NSApp object }
FNSApp := InitApplication;
FNSApp_Delegate := TAppDelegate.alloc.init;
FNSApp.setDelegate(FNSApp_Delegate);
{$ifdef COCOALOOPOVERRIDE}
FNSApp.finishLaunching;
{$endif}
// Sandboxing
lDict := NSProcessInfo.processInfo.environment;
SandboxingOn := lDict.valueForKey(NSStr('APP_SANDBOX_CONTAINER_ID')) <> nil;
end;
procedure TCocoaWidgetSet.SendCheckSynchronizeMessage;
begin
InitApplication
.performSelectorOnMainThread_withObject_waitUntilDone(
ObjCSelector('lclSyncCheck:'), nil, false);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.OnWakeMainThread
Params: Sender
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.OnWakeMainThread(Sender: TObject);
begin
SendCheckSynchronizeMessage;
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppRun
Params: ALoop
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
begin
if Assigned(ALoop) then
begin
TCocoaApplication(NSApp).aloop:=ALoop;
NSApp.run();
end;
end;
procedure TCocoaWidgetSet.AppRunMessages(onlyOne: Boolean; eventExpDate: NSDate);
var
event: NSEvent;
pool:NSAutoReleasePool;
begin
repeat
pool := NSAutoreleasePool.alloc.init;
{$ifdef BOOLFIX}
event := NSApp.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask, eventExpDate, NSDefaultRunLoopMode, Ord(true));
{$else}
event := NSApp.nextEventMatchingMask_untilDate_inMode_dequeue(NSAnyEventMask, eventExpDate, NSDefaultRunLoopMode, true);
{$endif}
if event <> nil then
begin
NSApp.sendEvent(event);
NSApp.updateWindows;
end;
SyncClipboard(); // NSPasteboard doesn't provide any notifications regarding the change
// Thus we have to check the clipboard on every loop
pool.release;
until onlyOne or (event = nil);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppProcessMessages
Handle all pending messages
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppProcessMessages;
begin
AppRunMessages(false, nil);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppWaitMessage
Passes execution control to Cocoa
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppWaitMessage;
begin
AppRunMessages(true, NSDate.distantFuture);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.Create
Constructor for the class
------------------------------------------------------------------------------}
constructor TCocoaWidgetSet.Create;
begin
CocoaWidgetSet := Self;
inherited Create;
FTerminating := False;
FCurrentCursor:= 0;
FCaptureControl:= 0;
NSMessageWnd := NSStringUTF8('HWND');
NSMessageMsg := NSStringUTF8('MSG');
NSMessageWParam := NSStringUTF8('WPARAM');
NSMessageLParam := NSStringUTF8('LPARAM');
NSMessageResult := NSStringUTF8('RESULT');
DefaultBrush := TCocoaBrush.CreateDefault(True);
DefaultPen := TCocoaPen.CreateDefault(True);
DefaultFont := TCocoaFont.CreateDefault(True);
DefaultBitmap := TCocoaBitmap.CreateDefault;
DefaultContext := TCocoaBitmapContext.Create;
DefaultContext.Bitmap := DefaultBitmap;
ScreenContext := TCocoaContext.Create(DefaultContext.ctx);
InitStockItems;
fClipboard := TCocoaWSClipboard.Create; // must be here otherwise clipboard calls before Application.Initialize crash
ToCollect := TList.Create;
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.Destroy
Destructor for the class
------------------------------------------------------------------------------}
destructor TCocoaWidgetSet.Destroy;
begin
ReleaseToCollect(0);
inherited Destroy;
FreeStockItems;
ScreenContext.Free;
DefaultContext.Free;
DefaultBitmap.Free;
DefaultFont.Free;
DefaultPen.Free;
DefaultBrush.Free;
FreeSysColorBrushes;
fClipboard.Free;
// The CocoaCaret is based WidgetSet timer.
// The GlobalCaret is freed in finalization section, which is called
// after the destruction of the widgetset and will cause a failure.
// Need to destroy the caret here.. or CustomTimer must be verified.
// or CocoaCaret should not use TTimer at all (use raw cocoa timer)
DestroyGlobalCaret;
NSMessageWnd.release;
NSMessageMsg.release;
NSMessageWParam.release;
NSMessageLParam.release;
NSMessageResult.release;
// NSApp.terminate(nil); // causes app to quit immediately, which is undesirable
// Must release the Main autorelease pool here.
// Some objects still in the pool my depend on releasing Widgetset objects
// (i.e. images). If autorelease pool is released After the widgetset object
// then it finalization of WS dependent objects would fail (suppressed AVs)
// and would cause leaks. (see #35400)
InternalFinal;
ToCollect.Free;
CocoaWidgetSet := nil;
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppTerminate
Tells Cocoa to halt the application
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppTerminate;
begin
if FTerminating then Exit;
// TODO: Check if there is more cleanup to do here
// NSApp.terminate(nil); // causes app to quit immediately, which is undesirable
{$ifdef COCOALOOPNATIVE}
NSApp.stop(nil);
{$endif}
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppMinimize
Minimizes the whole application to the taskbar
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppMinimize;
begin
NSApp.hide(NSApp);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppRestore
Restores the whole minimized application from the taskbar
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppRestore;
begin
NSApp.unhide(NSApp);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppBringToFront
Brings the entire application on top of all other non-topmost programs
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppBringToFront;
begin
{$ifdef BOOLFIX}
NSApp.activateIgnoringOtherApps_(Ord(True));
{$else}
NSApp.activateIgnoringOtherApps(True);
{$endif}
end;
procedure TCocoaWidgetSet.AppSetIcon(const Small, Big: HICON);
begin
if Big <> 0 then
NSApp.setApplicationIconImage(TCocoaBitmap(Big).image)
else
NSApp.setApplicationIconImage(nil);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.AppSetTitle
Params: ATitle - New application title
Changes the application title
------------------------------------------------------------------------------}
procedure TCocoaWidgetSet.AppSetTitle(const ATitle: string);
begin
// There is no way to change the dock title
end;
function TCocoaWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;
begin
case ACapability of
lcCanDrawOutsideOnPaint,
lcNeedMininimizeAppWithMainForm,
lcApplicationTitle,
{$ifndef COCOA_USE_NATIVE_MODAL}
lcModalWindow,
{$endif}
lcReceivesLMClearCutCopyPasteReliably:
Result := LCL_CAPABILITY_NO;
{$ifdef COCOA_USE_NATIVE_MODAL}
lcModalWindow,
{$endif}
lcFormIcon,
lcAntialiasingEnabledByDefault,
lcTransparentWindow,
lcCanDrawHidden:
Result := LCL_CAPABILITY_YES;
lcAccelleratorKeys:
Result := LCL_CAPABILITY_NO;
lcTextHint:
if NSAppKitVersionNumber >= NSAppKitVersionNumber10_10 then
Result := LCL_CAPABILITY_YES
else
Result := LCL_CAPABILITY_NO;
else
Result := inherited;
end;
end;
function TCocoaWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc): THandle;
var
timer : NSTimer;
user : TCocoaTimerObject;
begin
{$IFDEF VerboseObject}
DebugLn('TCocoaWidgetSet.CreateTimer');
{$ENDIF}
user:=TCocoaTimerObject.newWithFunc(TimerFunc);
timer:=NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats(
Interval/1000, user, objcselector(user.timerEvent), user, True);
// adding timer to all "common" loop mode.
NSRunLoop.currentRunLoop.addTimer_forMode(timer, NSDefaultRunLoopMode);
NSRunLoop.currentRunLoop.addTimer_forMode(timer, NSModalPanelRunLoopMode);
NSRunLoop.currentRunLoop.addTimer_forMode(timer, NSEventTrackingRunLoopMode);
{user is retained (twice, because it's target), by the timer and }
{released (twice) on timer invalidation}
user.release;
Result:=THandle(timer);
end;
function TCocoaWidgetSet.DestroyTimer(TimerHandle: THandle): boolean;
var
obj : NSObject;
begin
{$IFDEF VerboseObject}
DebugLn('TCocoaWidgetSet.DestroyTimer');
{$ENDIF}
obj:=NSObject(TimerHandle);
try
Result:= Assigned(obj) and obj.isKindOfClass_(NSTimer);
except
Result:=false;
end;
if not Result then Exit;
NSTimer(obj).invalidate;
end;
procedure TCocoaWidgetSet.InitStockItems;
var
LogBrush: TLogBrush;
logPen: TLogPen;
pool: NSAutoreleasePool;
begin
FillChar(LogBrush, SizeOf(TLogBrush),0);
LogBrush.lbStyle := BS_NULL;
FStockNullBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogBrush.lbStyle := BS_SOLID;
LogBrush.lbColor := $000000;
FStockBlackBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogBrush.lbColor := $C0C0C0;
FStockLtGrayBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogBrush.lbColor := $808080;
FStockGrayBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogBrush.lbColor := $404040;
FStockDkGrayBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogBrush.lbColor := $FFFFFF;
FStockWhiteBrush := HBrush(TCocoaBrush.Create(LogBrush, True));
LogPen.lopnStyle := PS_NULL;
LogPen.lopnWidth := Types.Point(0, 0); // create cosmetic pens
LogPen.lopnColor := $FFFFFF;
FStockNullPen := HPen(TCocoaPen.Create(LogPen, True));
LogPen.lopnStyle := PS_SOLID;
FStockWhitePen := HPen(TCocoaPen.Create(LogPen, True));
LogPen.lopnColor := $000000;
FStockBlackPen := HPen(TCocoaPen.Create(LogPen, True));
FStockSystemFont := HFont(TCocoaFont.CreateDefault(True));
pool := NSAutoreleasePool.alloc.init;
FStockFixedFont := HFont(TCocoaFont.Create(NSFont.userFixedPitchFontOfSize(0), True));
pool.release;
end;
procedure TCocoaWidgetSet.FreeStockItems;
procedure DeleteAndNilObject(var h: HGDIOBJ);
begin
if h <> 0 then
TCocoaGDIObject(h).Global := False;
DeleteObject(h);
h := 0;
end;
begin
DeleteAndNilObject(FStockNullBrush);
DeleteAndNilObject(FStockBlackBrush);
DeleteAndNilObject(FStockLtGrayBrush);
DeleteAndNilObject(FStockGrayBrush);
DeleteAndNilObject(FStockDkGrayBrush);
DeleteAndNilObject(FStockWhiteBrush);
DeleteAndNilObject(FStockNullPen);
DeleteAndNilObject(FStockBlackPen);
DeleteAndNilObject(FStockWhitePen);
DeleteAndNilObject(FStockFixedFont);
DeleteAndNilObject(FStockSystemFont);
end;
procedure TCocoaWidgetSet.FreeSysColorBrushes;
procedure DeleteAndNilObject(var h: HBrush);
begin
if h <> 0 then
begin
TCocoaBrush(h).Free;
h := 0;
end;
end;
var
i: integer;
begin
for i := Low(FSysColorBrushes) to High(FSysColorBrushes) do
DeleteAndNilObject(FSysColorBrushes[i]);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.GetAppHandle
Returns: Returns NSApp object, created via NSApplication.sharedApplication
------------------------------------------------------------------------------}
function TCocoaWidgetSet.GetAppHandle: THandle;
begin
Result:=THandle(NSApp);
end;
function TCocoaWidgetSet.CreateThemeServices: TThemeServices;
begin
Result:=TCocoaThemeServices.Create;
end;
function TCocoaWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor;
begin
Result := 0;
if CanvasHandle <> 0 then
Result := TCocoaContext(CanvasHandle).GetPixel(X,Y);
end;
procedure TCocoaWidgetSet.DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor);
begin
if CanvasHandle <> 0 then
TCocoaContext(CanvasHandle).SetPixel(X,Y,AColor);
end;
procedure TCocoaWidgetSet.DCRedraw(CanvasHandle: HDC);
begin
if CanvasHandle <> 0 then
TCocoaContext(CanvasHandle).ctx.flushGraphics;
end;
procedure TCocoaWidgetSet.DCSetAntialiasing(CanvasHandle: HDC; AEnabled: Boolean);
begin
if CanvasHandle <> 0 then
TCocoaContext(CanvasHandle).SetAntialiasing(AEnabled);
end;
procedure TCocoaWidgetSet.SetDesigning(AComponent: TComponent);
begin
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.LCLPlatform
Returns: lpCocoa - enum value for Cocoa widgetset
------------------------------------------------------------------------------}
function TCocoaWidgetSet.LCLPlatform: TLCLPlatform;
begin
Result:= lpCocoa;
end;
{ TCocoaTimerObject }
procedure TCocoaTimerObject.timerEvent;
begin
if Assigned(@func) then func;
end;
class function TCocoaTimerObject.newWithFunc(afunc: TWSTimerProc): TCocoaTimerObject;
begin
Result:=alloc;
Result.func:=afunc;
end;
procedure TAppDelegate.application_openFiles(sender: NSApplication; filenames: NSArray);
var
lFiles: array of string;
lNSStr: NSString;
i: Integer;
begin
SetLength(lFiles, filenames.count);
for i := 0 to filenames.count-1 do
begin
lNSStr := NSString(filenames.objectAtIndex(i));
lFiles[i] := NSStringToString(lNSStr);
end;
Application.IntfDropFiles(lFiles);
if Application.MainForm<>nil then
Application.MainForm.IntfDropFiles(lFiles);
end;
procedure TAppDelegate.applicationDidHide(notification: NSNotification);
begin
Application.IntfAppMinimize;
end;
procedure TAppDelegate.applicationDidUnhide(notification: NSNotification);
begin
Application.IntfAppRestore;
end;
procedure TAppDelegate.applicationWillBecomeActive(notification: NSNotification
);
{$ifdef COCOA_ACTIVATION_REORDER}
var
app : NSApplication;
i: integer;
vis: Boolean;
info: PWinLevelOrder;
ord: NSArray;
{$endif}
begin
{$ifdef COCOA_ACTIVATION_REORDER}
app := NSApplication(NSApp);
ord := app.orderedWindows;
orderArrayCount := ord.count;
orderArray := GetMem(orderArrayCount * sizeof(TWinLevelOrder));
for i := 0 to orderArrayCount - 1 do
begin
info := @orderArray^[i];
info^.win := ord.objectAtIndex(i);
info^.lvl := info^.win.level;
info^.ord := info^.win.orderedIndex;
info^.vis := info^.win.isVisible;
end;
{$endif}
end;
procedure TAppDelegate.applicationDidBecomeActive(notification: NSNotification);
var
i : integer;
begin
{$ifdef COCOA_ACTIVATION_REORDER}
// Cocoa changes level and order of windows to it's liking
// (it happens between Will- and DidBecomeActive)
// for example Model windows becoming level 8,
// even if LCL set them to level 0 before.
// As a result the OrderedIndex also goes messed up.
// It's being restored here
for i := orderArrayCount -1 downto 0 do
begin
if not orderArray^[i].vis then continue;
orderArray^[i].win.setLevel( orderArray^[i].lvl );
orderArray^[i].win.setOrderedIndex( orderArray^[i].ord );
orderArray^[i].win.orderFrontRegardless;
end;
orderArrayCount := 0;
if orderArray <> nil then
begin
Freemem(orderArray);
orderArray := nil;
end;
{$endif}
Application.IntfAppActivate;
end;
procedure TAppDelegate.applicationDidResignActive(notification: NSNotification);
begin
Application.IntfAppDeactivate;
end;
procedure TAppDelegate.applicationDidChangeScreenParameters(notification: NSNotification);
begin
Screen.UpdateMonitors;
Screen.UpdateScreen;
end;
procedure TAppDelegate.applicationWillFinishLaunching(notification: NSNotification);
begin
NSAppleEventManager.sharedAppleEventManager.setEventHandler_andSelector_forEventClass_andEventID(
Self, ObjCSelector('handleQuitAppEvent:withReplyEvent:'), kCoreEventClass,
kAEQuitApplication);
end;
procedure TAppDelegate.handleQuitAppEvent_withReplyEvent(event: NSAppleEventDescriptor; replyEvent: NSAppleEventDescriptor);
{ Capture "Quit Application" Apple Events, either from system shutdown/logout
or sent by another application. Don't use [applicationShouldTerminate:]
because that terminates the app immediately after [applicationWillTerminate:]
returns, so there's no chance to run finalization blocks }
var
Cancel: Boolean;
Reason: NSAppleEventDescriptor;
begin
Cancel := False;
// Check if it's a system-wide event
Reason := event.attributeDescriptorForKeyword(kEventParamReason);
if (Reason <> nil) and
((Reason.typeCodeValue = kAEQuitAll) or
(reason.typeCodeValue = kAEReallyLogOut) or
(reason.typeCodeValue = kAERestart) or
(reason.typeCodeValue = kAEShutDown)) then
begin
Application.IntfQueryEndSession(Cancel);
if not Cancel then
Application.IntfEndSession;
end;
// Try to quit
if not Cancel then
Application.MainForm.Close;
// Let caller know if the shutdown was cancelled
if (not Application.Terminated) and (replyEvent.descriptorType <> typeNull) then
replyEvent.setParamDescriptor_forKeyword(NSAppleEventDescriptor.descriptorWithInt32(userCanceledErr), keyErrorNumber);
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.RawImage_DescriptionFromCocoaBitmap
Creates a rawimage description for a cocoabitmap
------------------------------------------------------------------------------}
function TCocoaWidgetSet.RawImage_DescriptionFromCocoaBitmap(out ADesc: TRawImageDescription; ABitmap: TCocoaBitmap): Boolean;
var
Prec, Shift: Byte;
BPR: Integer;
HasAlpha: Boolean;
begin
ADesc.Init;
case ABitmap.BitmapType of
cbtMono, cbtGray: ADesc.Format := ricfGray;
else
ADesc.Format := ricfRGBA;
end;
ADesc.Width := Round(ABitmap.image.size.width);
ADesc.Height := Round(ABitmap.image.size.Height);
//ADesc.PaletteColorCount := 0;
ADesc.BitOrder := riboReversedBits;
ADesc.ByteOrder := riboMSBFirst;
BPR := ABitmap.BytesPerRow;
if BPR and $F = 0 then ADesc.LineEnd := rileDQWordBoundary // 128bit aligned
else if BPR and $7 = 0 then ADesc.LineEnd := rileQWordBoundary // 64bit aligned
else if BPR and $3 = 0 then ADesc.LineEnd := rileWordBoundary // 32bit aligned
else if BPR and $1 = 0 then ADesc.LineEnd := rileByteBoundary // 8bit aligned
else ADesc.LineEnd := rileTight;
ADesc.LineOrder := riloTopToBottom;
ADesc.BitsPerPixel := ABitmap.BitsPerPixel;
ADesc.MaskBitOrder := riboReversedBits;
ADesc.MaskBitsPerPixel := 1;
ADesc.MaskLineEnd := rileByteBoundary;
// ADesc.MaskShift := 0;
ADesc.Depth := ABitmap.Depth;
Prec := ABitmap.BitsPerSample;
ADesc.RedPrec := Prec;
ADesc.GreenPrec := Prec;
ADesc.BluePrec := Prec;
// gray or mono
if ADesc.Format = ricfGray then begin
Result := true;
Exit;
end;
// alpha
if ABitmap.BitmapType in [cbtARGB, cbtRGBA] then
ADesc.AlphaPrec := Prec;
HasAlpha := ABitmap.ImageRep.hasAlpha;
case ABitmap.BitmapType of
cbtRGB: begin
Shift := 24 - Prec;
ADesc.RedShift := Shift;
Dec(Shift, Prec);
ADesc.GreenShift := Shift;
Dec(Shift, Prec);
ADesc.BlueShift := Shift;
end;
cbtARGB: begin
Shift := 32 - Prec;
ADesc.AlphaShift := Shift;
Dec(Shift, Prec);
ADesc.RedShift := Shift;
Dec(Shift, Prec);
ADesc.GreenShift := Shift;
Dec(Shift, Prec);
ADesc.BlueShift := Shift;
end;
cbtRGBA: begin
Shift := 32 - Prec;
ADesc.RedShift := Shift;
Dec(Shift, Prec);
ADesc.GreenShift := Shift;
Dec(Shift, Prec);
ADesc.BlueShift := Shift;
Dec(Shift, Prec);
ADesc.AlphaShift := Shift;
end;
end;
Result := True;
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.RawImage_FromCocoaBitmap
Creates a rawimage description for a cocoabitmap
------------------------------------------------------------------------------}
function TCocoaWidgetSet.RawImage_FromCocoaBitmap(out ARawImage: TRawImage; ABitmap, AMask: TCocoaBitmap; ARect: PRect = nil): Boolean;
var
lBitmapData: PByte;
begin
FillChar(ARawImage, SizeOf(ARawImage), 0);
RawImage_DescriptionFromCocoaBitmap(ARawImage.Description, ABitmap);
ARawImage.DataSize := ABitmap.DataSize;
ReAllocMem(ARawImage.Data, ARawImage.DataSize);
lBitmapData := ABitmap.GetNonPreMultipliedData();
if ARawImage.DataSize > 0 then
System.Move(lBitmapData^, ARawImage.Data^, ARawImage.DataSize);
Result := True;
if AMask = nil then
begin
ARawImage.Description.MaskBitsPerPixel := 0;
Exit;
end;
if AMask.Depth > 1
then begin
DebugLn('[WARNING] RawImage_FromCocoaBitmap: AMask.Depth > 1');
Exit;
end;
ARawImage.MaskSize := AMask.DataSize;
ReAllocMem(ARawImage.Mask, ARawImage.MaskSize);
if ARawImage.MaskSize > 0 then
System.Move(AMask.Data^, ARawImage.Mask^, ARawImage.MaskSize);
end;
function TCocoaWidgetSet.RawImage_DescriptionToBitmapType(
ADesc: TRawImageDescription;
out bmpType: TCocoaBitmapType): Boolean;
begin
Result := False;
if ADesc.Format = ricfGray
then
begin
if ADesc.Depth = 1 then bmpType := cbtMono
else bmpType := cbtGray;
end
else if ADesc.Depth = 1
then bmpType := cbtMono
else if ADesc.AlphaPrec <> 0
then begin
if ADesc.ByteOrder = riboMSBFirst
then begin
if (ADesc.AlphaShift = 24)
and (ADesc.RedShift = 16)
and (ADesc.GreenShift = 8 )
and (ADesc.BlueShift = 0 )
then bmpType := cbtARGB
else
if (ADesc.AlphaShift = 24)
and (ADesc.RedShift = 0 )
and (ADesc.GreenShift = 8 )
and (ADesc.BlueShift = 16)
then bmpType := cbtABGR
else
if (ADesc.AlphaShift = 0 )
and (ADesc.RedShift = 24)
and (ADesc.GreenShift = 16)
and (ADesc.BlueShift = 8 )
then bmpType := cbtRGBA
else
if (ADesc.AlphaShift = 0 )
and (ADesc.RedShift = 8 )
and (ADesc.GreenShift = 16)
and (ADesc.BlueShift = 24)
then bmpType := cbtBGRA
else Exit;
end
else begin
if (ADesc.AlphaShift = 0 )
and (ADesc.RedShift = 8 )
and (ADesc.GreenShift = 16)
and (ADesc.BlueShift = 24)
then bmpType := cbtARGB
else
if (ADesc.AlphaShift = 0 )
and (ADesc.RedShift = 24)
and (ADesc.GreenShift = 16)
and (ADesc.BlueShift = 8 )
then bmpType := cbtABGR
else
if (ADesc.AlphaShift = 24)
and (ADesc.RedShift = 0 )
and (ADesc.GreenShift = 8 )
and (ADesc.BlueShift = 16)
then bmpType := cbtRGBA
else
if (ADesc.AlphaShift = 24)
and (ADesc.RedShift = 16)
and (ADesc.GreenShift = 8 )
and (ADesc.BlueShift = 0 )
then bmpType := cbtBGRA
else Exit;
end;
end
else begin
bmpType := cbtRGB;
end;
Result := True;
end;