1 {
2  *****************************************************************************
3   This file is part of the Printer4Lazarus package
4 
5   See the file COPYING.modifiedLGPL.txt, included in this distribution,
6   for details about the license.
7  *****************************************************************************
8 
9  custom-page in cocoa example:
10   https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Printing/osxp_pagination/osxp_pagination.html
11 }
12 unit cocoaprintcanvas;
13 
14 {$mode objfpc}{$H+}
15 {$modeswitch objectivec1}
16 
17 interface
18 
19 uses
20   // fpc
21   MacOSAll, CocoaAll, Classes, SysUtils, fpcanvas, Contnrs, Types,
22   // lcl-widgetset
23   CocoaUtils, CocoaGDIObjects,
24   // lcl
25   Printers, LCLType, Graphics;
26 
27 type
28 
29   { TCanvasOperation }
30 
31   TCanvasOperation = class(TObject)
32   public
33     procedure DrawTo(const ADest: TCocoaContext); virtual; abstract;
34   end;
35 
36   { TCanvasOperation_Pen }
37 
38   TCanvasOperation_Pen = class(TCanvasOperation)
39   public
40     Pen_Color: TColor; // default clBlack;
41     Pen_Cosmetic: Boolean; // default True;
42     Pen_Style: TFPPenStyle;
43     Pen_Width: Integer;
44     Pen_Mode: TFPPenMode;
45     Pen_EndCap: TFPPenEndCap;
46     Pen_JoinStyle: TFPPenJoinStyle;
47     //
48     DisablePen: Boolean; // for descendents to disable pen setting in DrawTo
49     procedure DrawTo(const ADest: TCocoaContext); override;
50   end;
51 
52   { TCanvasOperation_Pen_Brush }
53 
54   TCanvasOperation_Pen_Brush = class(TCanvasOperation_Pen)
55   public
56     Brush_Color: TColor; // default clBlack;
57     Brush_Style: TFPBrushStyle;
58     Brush_Pattern: TBrushPattern;
59     procedure DrawTo(const ADest: TCocoaContext); override;
60   end;
61 
62   TCanvasOperation_Font = class(TCanvasOperation_Pen_Brush)
63   public
64     Font_Name: string;
65     Font_Size: integer;
66     Font_Bold: boolean;
67     Font_Italic: boolean;
68     Font_Underline: boolean;
69     Font_StrikeThrough: boolean;
70     Font_Orientation: Integer;
71     //
72     Font_Pitch: TFontPitch;
73     Font_Quality: TFontQuality;
74     procedure DrawTo(const ADest: TCocoaContext); override;
75   end;
76 
77   { TCanvasOperation_Ellipse }
78 
79   TCanvasOperation_Ellipse = class(TCanvasOperation_Pen_Brush)
80   public
81     X1, Y1, X2, Y2: Integer;
82     constructor Create(AX1, AY1, AX2, AY2: Integer);
83     procedure DrawTo(const ADest: TCocoaContext); override;
84   end;
85 
86   TCanvasOperation_Rectangle = class(TCanvasOperation_Pen_Brush)
87   public
88     X1, Y1, X2, Y2: Integer;
89     constructor Create(AX1, AY1, AX2, AY2: Integer);
90     procedure DrawTo(const ADest: TCocoaContext); override;
91   end;
92 
93   TCanvasOperation_TextOut = class(TCanvasOperation_Font)
94   public
95     X, Y: Integer;
96     Text: string;
97     constructor Create(AX, AY: Integer; AText: string);
98     procedure DrawTo(const ADest: TCocoaContext); override;
99   end;
100 
101   { TCocoaPrinterCanvas }
102 
103   TCocoaPrinterCanvas = class(TFilePrinterCanvas)
104   private
105     FLazClipRect: TRect;
106     FRecordingPages: TFPObjectList; // list of 1 (FCurRecording: TFPObjectList) per page
107     FCurRecording: TFPObjectList; // this is the current recording
SetCurPagenull108     function SetCurPage(APageNum: Integer): Boolean;
GetOperationCountnull109     function GetOperationCount: Integer;
GetOperationnull110     function GetOperation(ANum: Integer): TCanvasOperation;
111     procedure SetPenProperties(ADest: TCanvasOperation_Pen);
112     procedure SetBrushProperties(ADest: TCanvasOperation_Pen_Brush);
113     procedure SetFontProperties(ADest: TCanvasOperation_Font);
114     procedure SetPenAndBrush(ADest: TCanvasOperation_Pen_Brush);
115     procedure SetFontAndBrush(ADest: TCanvasOperation_Font);
116   protected
117     ScaleX, ScaleY, FontScale: Double;
118     procedure SetLazClipRect(r: TRect);
119     procedure DoLineTo(X1,Y1: Integer); override;
120     procedure DoMoveTo({%H-}x, {%H-}y: integer); override;
121     procedure SetHandle(NewHandle: HDC); override;
GetClipRectnull122     function GetClipRect: TRect; override;
123     procedure SetClipRect(const ARect: TRect); override;
GetClippingnull124     function GetClipping: Boolean; override;
125     procedure SetClipping(const AValue: boolean); override;
126     //
127     procedure CreateBrush; override;
128     procedure CreateFont; override;
129     procedure CreateHandle; override;
130     procedure CreatePen; override;
131     procedure CreateRegion; override;
132     procedure RealizeAntialiasing; override;
133     procedure DestroyHandle;
134   public
135     SurfaceXDPI, SurfaceYDPI: Integer;
136     constructor Create(APrinter : TPrinter); override;
137     constructor Create; overload;
138     destructor Destroy; override;
139     procedure BeginDoc; override;
140     procedure EndDoc; override;
141     procedure NewPage; override;
142     procedure FillRect(const ARect: TRect); override;
143     procedure Rectangle(X1,Y1,X2,Y2: Integer); override;
144     procedure Polyline(Points: PPoint; NumPts: Integer); override;
145     procedure Polygon(Points: PPoint; NumPts: Integer; {%H-}Winding: boolean = False); override;
146     procedure FrameRect(const ARect: TRect); override;
147     procedure Frame(const ARect: TRect); override;
148     procedure RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer); override;
149     procedure Ellipse(X1, Y1, X2, Y2: Integer); override;
150     procedure Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer); override;
151     procedure Arc(ALeft, ATop, ARight, ABottom, StX, StY, EX, EY: Integer); override;
152     procedure Chord(X1, Y1, X2, Y2, Angle1, Angle2: Integer); override;
153     procedure Chord(X1, Y1, X2, Y2, StX, StY, EX, EY: Integer); override;
154     procedure Pie(EllipseX1, EllipseY1, EllipseX2, EllipseY2, StartX, StartY, EndX, EndY: Integer); override;
155     procedure RadialPie(Left, Top, Right, Bottom, Angle1, Angle2: Integer); override;
156     procedure PolyBezier(Points: PPoint; NumPts: Integer; Filled: boolean = False; Continuous: boolean = False); override;
157     procedure TextOut(X,Y: Integer; const Text: String); override;
158     procedure TextRect(ARect: TRect; X1, Y1: integer; const Text: string; const Style: TTextStyle); override;
TextExtentnull159     function TextExtent(const Text: string): TSize; override;
GetTextMetricsnull160     function GetTextMetrics(out M: TLCLTextMetric): boolean; override;
161     procedure StretchDraw(const DestRect: TRect; SrcGraphic: TGraphic); override;
162     procedure SetPixel(X,Y: Integer; Value: TColor); override;
163   public
164     procedure DrawRecording(const ADest: NSView; dirtyRect: NSRect; APageNum: Integer);
165   end;
166 
167 implementation
168 
169 { TCanvasOperation_Pen }
170 
171 procedure TCanvasOperation_Pen.DrawTo(const ADest: TCocoaContext);
172 var
173   lCocoaPen: TCocoaPen;
174 begin
175   if DisablePen then Exit;
176 
177   lCocoaPen := TCocoaPen.Create(Pen_Color, Pen_Style, Pen_Cosmetic,
178     Pen_Width, Pen_Mode, Pen_EndCap, Pen_JoinStyle);
179   lCocoaPen.Apply(ADest);
180   lCocoaPen.Free;
181 end;
182 
183 { TCanvasOperation_Pen_Brush }
184 
185 procedure TCanvasOperation_Pen_Brush.DrawTo(const ADest: TCocoaContext);
186 var
187   lCocoaBrush: TCocoaBrush;
188 begin
189   inherited DrawTo(ADest);
190   lCocoaBrush := TCocoaBrush.Create(Brush_Color, Brush_Style, Brush_Pattern);
191   lCocoaBrush.Apply(ADest);
192   lCocoaBrush.Free;
193 end;
194 
195 { TCanvasOperation_Font }
196 
197 procedure TCanvasOperation_Font.DrawTo(const ADest: TCocoaContext);
198 const
199   LF_BOOL: array[Boolean] of Byte = (0, 255);
200   LF_WEIGHT: array[Boolean] of Integer = (FW_NORMAL, FW_BOLD);
201   LF_QUALITY: array[TFontQuality] of Integer = (DEFAULT_QUALITY,
202     DRAFT_QUALITY, PROOF_QUALITY, NONANTIALIASED_QUALITY, ANTIALIASED_QUALITY,
203     CLEARTYPE_QUALITY, CLEARTYPE_NATURAL_QUALITY);
204 var
205   lLogFont: TLogFont;
206   lCocoaFont: TCocoaFont;
207 begin
208   lLogFont.lfHeight := Font_Size;
209   lLogFont.lfWidth := 0;
210   lLogFont.lfEscapement := Font_Orientation;
211   lLogFont.lfOrientation := Font_Orientation;
212   lLogFont.lfWeight := LF_WEIGHT[Font_Bold];
213   lLogFont.lfItalic := LF_BOOL[Font_Italic];
214   lLogFont.lfUnderline := LF_BOOL[Font_Underline];
215   lLogFont.lfStrikeOut := LF_BOOL[Font_StrikeThrough];
216   lLogFont.lfCharSet := DEFAULT_CHARSET;
217   lLogFont.lfOutPrecision := OUT_DEFAULT_PRECIS;
218   lLogFont.lfClipPrecision := CLIP_DEFAULT_PRECIS;
219   lLogFont.lfQuality := LF_QUALITY[Font_Quality];
220   case Font_Pitch of
221     fpVariable: lLogFont.lfPitchAndFamily := VARIABLE_PITCH;
222     fpFixed:    lLogFont.lfPitchAndFamily := FIXED_PITCH;
223   else
224     lLogFont.lfPitchAndFamily := DEFAULT_PITCH;
225   end;
226 
227   lLogFont.lfFaceName := Font_Name;
228 
229   {lCocoaFont := TCocoaFont.Create(lLogFont, Font_Name);
230   ADest.Font.Free;
231   ADest.Font := lCocoaFont;}
232 
233   inherited DrawTo(ADest);
234 end;
235 
236 { TCanvasOperation_Ellipse }
237 
238 constructor TCanvasOperation_Ellipse.Create(AX1, AY1, AX2, AY2: Integer);
239 begin
240   inherited Create;
241   X1 := AX1;
242   Y1 := AY1;
243   X2 := AX2;
244   Y2 := AY2;
245 end;
246 
247 procedure TCanvasOperation_Ellipse.DrawTo(const ADest: TCocoaContext);
248 begin
249   inherited DrawTo(ADest); // apply pen and brush
250   ADest.Ellipse(X1, Y1, X2, Y2);
251 end;
252 
253 { TCanvasOperation_Rectangle }
254 
255 constructor TCanvasOperation_Rectangle.Create(AX1, AY1, AX2, AY2: Integer);
256 begin
257   inherited Create;
258   X1 := AX1;
259   Y1 := AY1;
260   X2 := AX2;
261   Y2 := AY2;
262 end;
263 
264 procedure TCanvasOperation_Rectangle.DrawTo(const ADest: TCocoaContext);
265 begin
266   inherited DrawTo(ADest); // apply pen and brush
267   ADest.Rectangle(X1, Y1, X2, Y2, True, nil);
268 end;
269 
270 { TCanvasOperation_TextOut }
271 
272 constructor TCanvasOperation_TextOut.Create(AX, AY: Integer; AText: string);
273 begin
274   inherited Create;
275   DisablePen := True;
276   X := AX;
277   Y := AY;
278   Text := AText;
279 end;
280 
281 procedure TCanvasOperation_TextOut.DrawTo(const ADest: TCocoaContext);
282 begin
283   inherited DrawTo(ADest); // apply pen and brush
284   ADest.TextOut(X, Y, 0, nil, PChar(Text), Length(Text), nil);
285 end;
286 
287 { TCocoaPrinterCanvas }
288 
SetCurPagenull289 function TCocoaPrinterCanvas.SetCurPage(APageNum: Integer): Boolean;
290 begin
291   Result := False;
292   if (APageNum < 0) or (APageNum >= FRecordingPages.Count) then Exit;
293   FCurRecording := TFPObjectList(FRecordingPages.Items[APageNum]);
294   Result := True;
295 end;
296 
TCocoaPrinterCanvas.GetOperationCountnull297 function TCocoaPrinterCanvas.GetOperationCount: Integer;
298 begin
299   Result := FCurRecording.Count;
300 end;
301 
GetOperationnull302 function TCocoaPrinterCanvas.GetOperation(ANum: Integer): TCanvasOperation;
303 begin
304   Result := TCanvasOperation(FCurRecording.Items[ANum]);
305 end;
306 
307 procedure TCocoaPrinterCanvas.SetPenProperties(ADest: TCanvasOperation_Pen);
308 begin
309   ADest.Pen_Color := Pen.Color;
310   ADest.Pen_Cosmetic := Pen.Cosmetic;
311   ADest.Pen_Style := Pen.Style;
312   ADest.Pen_Width := Pen.Width;
313   ADest.Pen_Mode := Pen.Mode;
314   ADest.Pen_EndCap := Pen.EndCap;
315   ADest.Pen_JoinStyle := Pen.JoinStyle;
316 end;
317 
318 procedure TCocoaPrinterCanvas.SetBrushProperties(ADest: TCanvasOperation_Pen_Brush);
319 begin
320   ADest.Brush_Color := Brush.Color;
321   ADest.Brush_Style := Brush.Style;
322   ADest.Brush_Pattern := Brush.Pattern;
323 end;
324 
325 procedure TCocoaPrinterCanvas.SetFontProperties(ADest: TCanvasOperation_Font);
326 begin
327 end;
328 
329 procedure TCocoaPrinterCanvas.SetPenAndBrush(ADest: TCanvasOperation_Pen_Brush);
330 begin
331   SetPenProperties(ADest);
332   SetBrushProperties(ADest);
333 end;
334 
335 procedure TCocoaPrinterCanvas.SetFontAndBrush(ADest: TCanvasOperation_Font);
336 begin
337   SetBrushProperties(ADest);
338   SetFontProperties(ADest);
339 end;
340 
341 procedure TCocoaPrinterCanvas.DoLineTo(X1, Y1: Integer);
342 begin
343   {Changing;
344   RequiredState([csHandleValid, csPenValid]);
345   SetPenProperties;
346   cairo_move_to(cr, SX(PenPos.X), SY(PenPos.Y));
347   cairo_line_to(cr, SX(X1), SY(Y1));
348   SetInternalPenPos(Point(X1,Y1));
349   StrokeOnly;
350   Changed;}
351 end;
352 
353 procedure TCocoaPrinterCanvas.DoMoveTo(x, y: integer);
354 begin
355   // should not call inherited DoMoveTo which would end calling
356   // interface MoveToEx which breaks things for Qt
357 end;
358 
359 procedure TCocoaPrinterCanvas.SetHandle(NewHandle: HDC);
360 begin
361   inherited SetHandle(NewHandle);
362 end;
363 
364 procedure TCocoaPrinterCanvas.BeginDoc;
365 begin
366   inherited BeginDoc;
367   if assigned(printer) then
368     FLazClipRect:=printer.PaperSize.PaperRect.WorkRect;
369 end;
370 
371 procedure TCocoaPrinterCanvas.EndDoc;
372 begin
373   inherited EndDoc;
374   {cairo_show_page(cr);
375   FLazClipRect := Rect(0, 0, 0, 0);
376   //if caller is printer, then at the end destroy cairo handles (flush output)
377   //and establishes CreateCairoHandle call on the next print}
378   Handle := 0;
379 end;
380 
381 procedure TCocoaPrinterCanvas.NewPage;
382 begin
383   inherited NewPage;
384   //cairo_show_page(cr);
385 end;
386 
387 procedure TCocoaPrinterCanvas.CreateBrush;
388 begin
389 end;
390 
391 procedure TCocoaPrinterCanvas.CreateFont;
392 begin
393 end;
394 
395 procedure TCocoaPrinterCanvas.CreateHandle;
396 begin
397   ScaleX := SurfaceXDPI/XDPI;
398   ScaleY := SurfaceYDPI/YDPI;
399 
400   if FRecordingPages = nil then
401   begin
402     FCurRecording := TFPObjectList.Create;
403     FRecordingPages := TFPObjectList.Create;
404     FRecordingPages.Add(FCurRecording);
405   end;
406   Handle := HWND(FRecordingPages);
407 end;
408 
409 procedure TCocoaPrinterCanvas.CreatePen;
410 begin
411 end;
412 
413 procedure TCocoaPrinterCanvas.CreateRegion;
414 begin
415 end;
416 
417 procedure TCocoaPrinterCanvas.RealizeAntialiasing;
418 begin
419 end;
420 
421 procedure TCocoaPrinterCanvas.DestroyHandle;
422 var
423   i: Integer;
424 begin
425   for i := 0 to FRecordingPages.Count-1 do
426     FRecordingPages.Items[i].Free;
427   FCurRecording := nil;
428 end;
429 
TCocoaPrinterCanvas.GetClipRectnull430 function TCocoaPrinterCanvas.GetClipRect: TRect;
431 var
432   x1,y1,x2,y2: double;
433 begin
434   RequiredState([csHandleValid]);
435 
436   {// it doesn't matter what the clip is in use, default or user
437   // this returns always the current clip
438 
439   result.Left:=round(x1/ScaleX);
440   result.Top:=round(y1/ScaleY);
441   result.Right:=round(x2/ScaleX);
442   result.Bottom:=round(y2/ScaleY);}
443 end;
444 
445 procedure TCocoaPrinterCanvas.SetClipRect(const ARect: TRect);
446 begin
447   {RequiredState([csHandleValid]);
448   if FUserClipRect=nil then
449     New(FUserClipRect);
450 
451   fUserClipRect^.x := SX(ARect.Left);
452   fUserClipRect^.y := SY(ARect.Top);
453   fUserClipRect^.width := SX2(ARect.Right-ARect.Left);
454   fUserClipRect^.height:= SY2(ARect.Bottom-ARect.Top);
455   }
456 end;
457 
TCocoaPrinterCanvas.GetClippingnull458 function TCocoaPrinterCanvas.GetClipping: Boolean;
459 begin
460   //result := (fUserClipRect<>nil);
461 end;
462 
463 procedure TCocoaPrinterCanvas.SetClipping(const AValue: boolean);
464 begin
465   RequiredState([csHandleValid]);
466   {cairo_reset_clip(cr);
467 
468   if not AValue then begin
469     // free user cliprect if exists
470     if fUserClipRect<>nil then
471       Dispose(fUserClipRect);
472     fUserClipRect := nil;
473   end
474   else begin
475     if fUserClipRect<>nil then
476     begin
477       with fUserClipRect^ do
478       begin
479         cairo_rectangle(cr, x, y, width, height);
480         cairo_clip(cr);
481       end;
482     end else
483       ; // cairo_reset_clip always clip
484   end;}
485 end;
486 
487 procedure TCocoaPrinterCanvas.SetLazClipRect(r: TRect);
488 begin
489   FLazClipRect := r;
490 end;
491 
492 constructor TCocoaPrinterCanvas.Create(APrinter: TPrinter);
493 begin
494   inherited Create(APrinter);
495   ScaleX := 1;
496   ScaleY := 1;
497   FontScale := 1;
498   SurfaceXDPI := 72;
499   SurfaceYDPI := 72;
500   XDPI := SurfaceXDPI;
501   YDPI := SurfaceXDPI;
502 
503   CreateHandle;
504 end;
505 
506 constructor TCocoaPrinterCanvas.Create;
507 begin
508   Create(nil);
509 end;
510 
511 destructor TCocoaPrinterCanvas.Destroy;
512 begin
513   DestroyHandle;
514 
515   inherited Destroy;
516 end;
517 
518 procedure TCocoaPrinterCanvas.Rectangle(X1, Y1, X2, Y2: Integer);
519 var
520   lRect: TCanvasOperation_Rectangle;
521 begin
522   Changing;
523   RequiredState([csHandleValid, csPenValid, csBrushValid]);
524   lRect := TCanvasOperation_Rectangle.Create(X1, Y1, X2, Y2);
525   SetPenAndBrush(lRect);
526   FCurRecording.Add(lRect);
527   Changed;
528 end;
529 
530 //1 point rectangle in _Brush_ color
531 procedure TCocoaPrinterCanvas.FrameRect(const ARect: TRect);
532 begin
533   {Changing;
534   RequiredState([csHandleValid, csBrushValid]);
535   cairo_rectangle(cr, SX(ARect.Left), SY(ARect.Top), SX2(ARect.Right-ARect.Left), SY2(ARect.Bottom-ARect.Top));
536   SetSourceColor(Brush.Color);
537   cairo_set_line_width(cr, 1);
538   cairo_stroke(cr); //Don't touch
539   Changed;}
540 end;
541 
542 procedure TCocoaPrinterCanvas.Frame(const ARect: TRect);
543 begin
544   {Changing;
545   RequiredState([csHandleValid, csPenValid]);
546   cairo_rectangle(cr, SX(ARect.Left), SY(ARect.Top), SX2(ARect.Right-ARect.Left), SY2(ARect.Bottom-ARect.Top));
547   cairo_set_line_width(cr, 1);
548   SetSourceColor(Pen.Color);
549   cairo_stroke(cr); //Don't touch
550   Changed;}
551 end;
552 
553 procedure TCocoaPrinterCanvas.RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer);
554 begin
555   {Changing;
556   RequiredState([csHandleValid, csPenValid, csBrushValid]);
557   cairo_move_to(cr, SX(X1+RX), SY(Y1));
558   cairo_line_to(cr, SX(X2-RX), SY(Y1));
559   EllipseArcPath(X2-RX, Y1+RY, RX, RY, -PI/2, 0, True, True);
560   cairo_line_to(cr, SX(X2), SY(Y2-RY));
561   EllipseArcPath(X2-RX, Y2-RY, RX, RY, 0, PI/2, True, True);
562   cairo_line_to(cr, SX(X1+RX), SY(Y2));
563   EllipseArcPath(X1+RX, Y2-RY, RX, RY, PI/2, PI, True, True);
564   cairo_line_to(cr, SX(X1), SY(Y1+RX));
565   EllipseArcPath(X1+RX, Y1+RY, RX, RY, PI, PI*1.5, True, True);
566   FillAndStroke;
567   Changed;}
568 end;
569 
570 procedure TCocoaPrinterCanvas.Ellipse(X1, Y1, X2, Y2: Integer);
571 var
572   lEllipse: TCanvasOperation_Ellipse;
573 begin
574   Changing;
575   RequiredState([csHandleValid, csPenValid, csBrushValid]);
576   lEllipse := TCanvasOperation_Ellipse.Create(X1, Y1, X2, Y2);
577   SetPenAndBrush(lEllipse);
578   FCurRecording.Add(lEllipse);
579   Changed;
580 end;
581 
582 procedure TCocoaPrinterCanvas.Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
583 begin
584   {Changing;
585   RequiredState([csHandleValid, csPenValid]);
586   ArcPath(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength);
587   StrokeOnly;
588   Changed;}
589 end;
590 
591 procedure TCocoaPrinterCanvas.Chord(X1, Y1, X2, Y2, Angle1, Angle2: Integer);
592 begin
593   {Changing;
594   RequiredState([csHandleValid, csPenValid, csBrushValid]);
595   ArcPath(X1, Y1, X2, Y2, Angle1, Angle2);
596   cairo_close_path(cr);
597   FillAndStroke;
598   Changed;}
599 end;
600 
601 procedure TCocoaPrinterCanvas.RadialPie(Left, Top, Right, Bottom, Angle1, Angle2: Integer);
602 {var
603   cx, cy: double;}
604 begin
605   {Changing;
606   RequiredState([csHandleValid, csPenValid, csBrushValid]);
607   ArcPath(Left, Top, Right, Bottom, Angle1, Angle2);
608   cx := (Right+Left)/2;
609   cy := (Bottom+Top)/2;
610   cairo_line_to(cr, SX(cx), SY(cy));
611   cairo_close_path(cr);
612   FillAndStroke;
613   Changed;}
614 end;
615 
616 procedure TCocoaPrinterCanvas.Arc(ALeft, ATop, ARight, ABottom, StX, StY, EX, EY: Integer);
617 begin
618   {Changing;
619   RequiredState([csHandleValid, csPenValid]);
620   ArcPath(ALeft, ATop, ARight, ABottom, StX, StY, EX, EY);
621   StrokeOnly;
622   Changed;}
623 end;
624 
625 procedure TCocoaPrinterCanvas.Chord(X1, Y1, X2, Y2, StX, StY, EX, EY: Integer);
626 begin
627   {Changing;
628   RequiredState([csHandleValid, csPenValid, csBrushValid]);
629   ArcPath(X1, Y1, X2, Y2, StX, StY, EX, EY);
630   cairo_close_path(cr);
631   FillAndStroke;
632   Changed;}
633 end;
634 
635 procedure TCocoaPrinterCanvas.Pie(EllipseX1, EllipseY1, EllipseX2, EllipseY2,
636   StartX, StartY, EndX, EndY: Integer);
637 var
638   cx, cy: double;
639 begin
640   {Changing;
641   RequiredState([csHandleValid, csPenValid, csBrushValid]);
642   ArcPath(EllipseX1, EllipseY1, EllipseX2, EllipseY2, StartX, StartY, EndX, EndY);
643   cx := (EllipseX2+EllipseX1)/2;
644   cy := (EllipseY2+EllipseY1)/2;
645   cairo_line_to(cr, SX(cx), SY(cy));
646   cairo_close_path(cr);
647   FillAndStroke;
648   Changed;}
649 end;
650 
651 procedure TCocoaPrinterCanvas.PolyBezier(Points: PPoint; NumPts: Integer; Filled: boolean; Continuous: boolean);
652 begin
653 end;
654 
655 procedure TCocoaPrinterCanvas.TextOut(X, Y: Integer; const Text: String);
656 var
657   lText: TCanvasOperation_TextOut;
658 begin
659   Changing;
660   RequiredState([csHandleValid, csPenValid, csBrushValid]);
661   lText := TCanvasOperation_TextOut.Create(X, Y, Text);
662   SetFontAndBrush(lText);
663   FCurRecording.Add(lText);
664   Changed;
665 end;
666 
667 procedure TCocoaPrinterCanvas.TextRect(ARect: TRect; X1, Y1: integer; const Text: string; const Style: TTextStyle);
668 var
669   s: string;
670 begin
671   Changing;
672   RequiredState([csHandleValid, csFontValid, csBrushValid]);
673   Changed;
674 end;
675 
TCocoaPrinterCanvas.TextExtentnull676 function TCocoaPrinterCanvas.TextExtent(const Text: string): TSize;
677 begin
678   RequiredState([csHandleValid, csFontValid]);
679   //SelectFont;
680 end;
681 
GetTextMetricsnull682 function TCocoaPrinterCanvas.GetTextMetrics(out M: TLCLTextMetric): boolean;
683 begin
684   {RequiredState([csHandleValid, csFontValid]);
685   SelectFont;
686   cairo_font_extents(cr, @e); //transformation matrix is here ignored
687   FillChar(M{%H-}, SizeOf(M), 0);
688   M.Ascender := Round(e.ascent/ScaleY);
689   M.Descender := Round(e.descent/ScaleY);
690   M.Height := Round(e.height/ScaleY);
691   Result := True;}
692 end;
693 
694 procedure TCocoaPrinterCanvas.StretchDraw(const DestRect: TRect; SrcGraphic: TGraphic);
695 begin
696 end;
697 
698 procedure TCocoaPrinterCanvas.SetPixel(X, Y: Integer; Value: TColor);
699 begin
700   {Changing;
701   RequiredState([csHandleValid, csPenValid]);
702   SetSourceColor(Value);
703   cairo_rectangle(cr, SX(X), SY(Y), 1, 1);
704   cairo_fill(cr);
705   Changed;}
706 end;
707 
708 procedure TCocoaPrinterCanvas.Polyline(Points: PPoint; NumPts: Integer);
709 begin
710   {if NumPts <= 0 then
711     Exit;
712   Changing;
713   RequiredState([csHandleValid, csPenValid]);
714   PolylinePath(Points, NumPts);
715   StrokeOnly;
716   Changed;}
717 end;
718 
719 procedure TCocoaPrinterCanvas.Polygon(Points: PPoint; NumPts: Integer; Winding: boolean);
720 begin
721   {if NumPts <= 0 then
722     Exit;
723   Changing;
724   RequiredState([csHandleValid, csBrushValid, csPenValid]);
725   PolylinePath(Points, NumPts);
726   cairo_close_path(cr);
727   FillAndStroke;
728   Changed;}
729 end;
730 
731 procedure TCocoaPrinterCanvas.FillRect(const ARect: TRect);
732 begin
733   {Changing;
734   RequiredState([csHandleValid, csBrushValid]);
735   cairo_rectangle(cr, SX(ARect.Left), SY(ARect.Top), SX2(ARect.Right-ARect.Left), SY2(ARect.Bottom-ARect.Top));
736   FillOnly;
737   Changed;}
738 end;
739 
740 procedure TCocoaPrinterCanvas.DrawRecording(const ADest: NSView; dirtyRect: NSRect; APageNum: Integer);
741 var
742   i: Integer;
743   lCurOperation: TCanvasOperation;
744   lCocoaContext: TCocoaContext;
745 begin
746   if not SetCurPage(APageNum) then Exit;
747   lCocoaContext := TCocoaContext.Create(NSGraphicsContext.currentContext);
748   for i := 0 to GetOperationCount()-1 do
749   begin
750     lCurOperation := GetOperation(i);
751     lCurOperation.DrawTo(lCocoaContext);
752   end;
753   lCocoaContext.Free;
754 end;
755 
756 end.
757 
758