Logo ROOT  
Reference Guide
X11Buffer.mm
Go to the documentation of this file.
1// @(#)root/graf2d:$Id$
2// Author: Timur Pocheptsov 29/02/2012
3
4/*************************************************************************
5 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//#define NDEBUG
13
14#include <stdexcept>
15#include <cstring>
16#include <cassert>
17#include <memory>
18
19#include <Cocoa/Cocoa.h>
20
21#include "ROOTOpenGLView.h"
22#include "CocoaPrivate.h"
23#include "QuartzWindow.h"
24#include "QuartzPixmap.h"
25#include "QuartzUtils.h"
26#include "X11Drawable.h"
27#include "X11Buffer.h"
28#include "TGWindow.h"
29#include "TGClient.h"
30#include "TGCocoa.h"
31#include "TError.h"
32
33namespace ROOT {
34namespace MacOSX {
35namespace X11 {
36
37//______________________________________________________________________________
39 : fID(wid),
40 fGC(gc)
41{
42}
43
44//______________________________________________________________________________
46 : fID(wid),
47 fGC()
48{
49}
50
51//______________________________________________________________________________
53{
54}
55
56//______________________________________________________________________________
58{
59}
60
61//______________________________________________________________________________
63{
64 return wid == fID;
65}
66
67//______________________________________________________________________________
69{
70 return false;
71}
72
73//______________________________________________________________________________
74DrawLine::DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
75 : Command(wid, gc),
76 fP1(p1),
77 fP2(p2)
78{
79}
80
81//______________________________________________________________________________
83{
84 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
85 "Execute, gVirtualX is either null or not of TGCocoa type");
86 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
87 vx->DrawLineAux(fID, fGC, fP1.fX, fP1.fY, fP2.fX, fP2.fY);
88}
89
90//______________________________________________________________________________
92 const Segment_t *segments, Int_t nSegments)
93 : Command(wid, gc)
94{
95 assert(segments != 0 && "DrawSegments, segments parameter is null");
96 assert(nSegments > 0 && "DrawSegments, nSegments <= 0");
97
98 fSegments.assign(segments, segments + nSegments);
99}
100
101//______________________________________________________________________________
103{
104 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
105 "Execute, gVirtualX is either null or not of TGCocoa type");
106 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
107 vx->DrawSegmentsAux(fID, fGC, &fSegments[0], (Int_t)fSegments.size());
108}
109
110//______________________________________________________________________________
112 : Command(wid),
113 fArea(area)
114{
115}
116
117//______________________________________________________________________________
119{
120 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
121 "Execute, gVirtualX is either null or not of TGCocoa type");
122 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
124}
125
126//______________________________________________________________________________
128 const Rectangle_t &area, const Point &dstPoint)
129 : Command(dst, gc),
130 fSrc(src),
131 fArea(area),
132 fDstPoint(dstPoint)
133{
134}
135
136//______________________________________________________________________________
138{
139 return fID == drawable || fSrc == drawable || fGC.fClipMask == drawable;
140}
141
142//______________________________________________________________________________
144{
145 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
146 "Execute, gVirtualX is either null or not of TGCocoa type");
147
148 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
151}
152
153//______________________________________________________________________________
155 const std::string &text)
156 : Command(wid, gc),
157 fPoint(point),
158 fText(text)
159{
160}
161
162//______________________________________________________________________________
164{
165 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
166 "Execute, gVirtualX is either null or not of TGCocoa type");
167
168 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
169 vx->DrawStringAux(fID, fGC, fPoint.fX, fPoint.fY, fText.c_str(), fText.length());
170}
171
172//______________________________________________________________________________
174 const Rectangle_t &rectangle)
175 : Command(wid, gc),
176 fRectangle(rectangle)
177{
178}
179
180//______________________________________________________________________________
182{
183 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
184 "Execute, gVirtualX is either null or not of TGCocoa type");
185
186 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
189}
190
191//______________________________________________________________________________
193 const Point_t *points, Int_t nPoints)
194 : Command(wid, gc)
195{
196 assert(points != 0 && "FillPolygon, points parameter is null");
197 assert(nPoints > 0 && "FillPolygon, nPoints <= 0");
198
199 fPolygon.assign(points, points + nPoints);
200}
201
202//______________________________________________________________________________
204{
205 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
206 "Execute, gVirtualX is either null or not of TGCocoa type");
207
208 ((TGCocoa *)gVirtualX)->FillPolygonAux(fID, fGC, &fPolygon[0], (Int_t)fPolygon.size());
209}
210
211//______________________________________________________________________________
213 const Rectangle_t &rectangle)
214 : Command(wid, gc),
215 fRectangle(rectangle)
216{
217}
218
219//______________________________________________________________________________
221{
222 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
223 "Execute, gVirtualX is either null or not of TGCocoa type");
224
225 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
228}
229
230//______________________________________________________________________________
232 : Command(view.fID),
233 fView(view)
234{
235 assert(view != nil && "UpdateWindow, view parameter is nil");//view.fID will be also 0.
236}
237
238//______________________________________________________________________________
240{
241 assert(fView.fContext != 0 && "Execute, view.fContext is null");
242
243 if (QuartzPixmap *pixmap = fView.fBackBuffer)
244 [fView copy : pixmap area : Rectangle(0, 0, pixmap.fWidth, pixmap.fHeight)
245 withMask : nil clipOrigin : Point() toPoint : Point()];
246}
247
248//______________________________________________________________________________
250 : Command(pixmap, GCValues_t())
251{
252}
253
254//______________________________________________________________________________
256{
257 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
258 "Execute, gVirtualX is either null or not of TGCocoa type");
259
260 ((TGCocoa *)gVirtualX)->DeletePixmapAux(fID);
261}
262
263//______________________________________________________________________________
264DrawBoxXor::DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
265 : Command(windowID, GCValues_t()),
266 fP1(p1),
267 fP2(p2)
268{
269 if (fP1.fX > fP2.fX)
271 if (fP1.fY > fP2.fY)
273}
274
275//______________________________________________________________________________
277{
278 //Noop.
279}
280
281//______________________________________________________________________________
283{
284 //
285 assert(ctx != 0 && "Execute, ctx parameter is null");
286
287 CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
288 CGContextSetLineWidth(ctx, 1.);
289
290 CGContextStrokeRect(ctx, CGRectMake(fP1.fX, fP1.fY, fP2.fX - fP1.fX, fP2.fY - fP1.fY));
291}
292
293//______________________________________________________________________________
294DrawLineXor::DrawLineXor(Window_t windowID, const Point &p1, const Point &p2)
295 : Command(windowID, GCValues_t()),
296 fP1(p1),
297 fP2(p2)
298{
299}
300
301//______________________________________________________________________________
303{
304 //Noop.
305}
306
307//______________________________________________________________________________
309{
310 //Noop.
311}
312
313//______________________________________________________________________________
315{
316}
317
318//______________________________________________________________________________
320{
323}
324
325//______________________________________________________________________________
327 Int_t y1, Int_t x2, Int_t y2)
328{
329 try {
330 //if this throws, I do not care.
331 std::unique_ptr<DrawLine> cmd(new DrawLine(wid, gc, Point(x1, y1), Point(x2, y2)));
332 fCommands.push_back(cmd.get());//this can throw.
333 cmd.release();
334 } catch (const std::exception &) {
335 throw;
336 }
337}
338
339//______________________________________________________________________________
341 const Segment_t *segments, Int_t nSegments)
342{
343 assert(segments != 0 && "AddDrawSegments, segments parameter is null");
344 assert(nSegments > 0 && "AddDrawSegments, nSegments <= 0");
345
346 try {
347 std::unique_ptr<DrawSegments> cmd(new DrawSegments(wid, gc, segments, nSegments));
348 fCommands.push_back(cmd.get());
349 cmd.release();
350 } catch (const std::exception &) {
351 throw;
352 }
353}
354
355//______________________________________________________________________________
357{
358 try {
359 Rectangle_t r = {};//To be replaced with X11::Rectangle.
360 r.fX = x;
361 r.fY = y;
362 r.fWidth = (UShort_t)w;
363 r.fHeight = (UShort_t)h;
364 std::unique_ptr<ClearArea> cmd(new ClearArea(wid, r));//Can throw, nothing leaks.
365 fCommands.push_back(cmd.get());//this can throw.
366 cmd.release();
367 } catch (const std::exception &) {
368 throw;
369 }
370}
371
372//______________________________________________________________________________
374 Int_t srcX, Int_t srcY, UInt_t width, UInt_t height,
375 Int_t dstX, Int_t dstY)
376{
377 try {
378 Rectangle_t area = {};
379 area.fX = srcX;
380 area.fY = srcY;
381 area.fWidth = (UShort_t)width;
382 area.fHeight = (UShort_t)height;
383 //Can throw, nothing leaks.
384 std::unique_ptr<CopyArea> cmd(new CopyArea(src, dst, gc, area, Point(dstX, dstY)));
385 fCommands.push_back(cmd.get());//this can throw.
386 cmd.release();
387 } catch (const std::exception &) {
388 throw;
389 }
390}
391
392//______________________________________________________________________________
394 const char *text, Int_t len)
395{
396 try {
397 if (len < 0)//Negative length can come from caller.
398 len = std::strlen(text);
399 const std::string substr(text, len);//Can throw.
400 std::unique_ptr<DrawString> cmd(new DrawString(wid, gc, Point(x, y), substr));//Can throw.
401 fCommands.push_back(cmd.get());//can throw.
402 cmd.release();
403 } catch (const std::exception &) {
404 throw;
405 }
406}
407
408//______________________________________________________________________________
410 Int_t x, Int_t y, UInt_t w, UInt_t h)
411{
412 try {
413 Rectangle_t r = {};
414 r.fX = x;
415 r.fY = y;
416 r.fWidth = (UShort_t)w;
417 r.fHeight = (UShort_t)h;
418 std::unique_ptr<FillRectangle> cmd(new FillRectangle(wid, gc, r));
419 fCommands.push_back(cmd.get());
420 cmd.release();
421 } catch (const std::exception &) {
422 throw;
423 }
424}
425
426//______________________________________________________________________________
428 Int_t x, Int_t y, UInt_t w, UInt_t h)
429{
430 try {
431 Rectangle_t r = {};
432 r.fX = x;
433 r.fY = y;
434 r.fWidth = (UShort_t)w;
435 r.fHeight = (UShort_t)h;
436 std::unique_ptr<DrawRectangle> cmd(new DrawRectangle(wid, gc, r));
437 fCommands.push_back(cmd.get());
438 cmd.release();
439 } catch (const std::exception &) {
440 throw;
441 }
442}
443
444//______________________________________________________________________________
446 const Point_t *polygon, Int_t nPoints)
447{
448 assert(polygon != 0 && "AddFillPolygon, polygon parameter is null");
449 assert(nPoints > 0 && "AddFillPolygon, nPoints <= 0");
450
451 try {
452 std::unique_ptr<FillPolygon> cmd(new FillPolygon(wid, gc, polygon, nPoints));
453 fCommands.push_back(cmd.get());
454 cmd.release();
455 } catch (const std::exception &) {
456 throw;
457 }
458}
459
460//______________________________________________________________________________
462{
463 assert(view != nil && "AddUpdateWindow, view parameter is nil");
464
465 try {
466 std::unique_ptr<UpdateWindow> cmd(new UpdateWindow(view));
467 fCommands.push_back(cmd.get());
468 cmd.release();
469 } catch (const std::exception &) {
470 throw;
471 }
472}
473
474//______________________________________________________________________________
476{
477 try {
478 std::unique_ptr<DeletePixmap> cmd(new DeletePixmap(pixmapID));
479 fCommands.push_back(cmd.get());
480 cmd.release();
481 } catch (const std::exception &) {
482 throw;
483 }
484}
485
486//______________________________________________________________________________
488{
489 try {
490 std::unique_ptr<DrawBoxXor> cmd(new DrawBoxXor(windowID, Point(x1, y1), Point(x2, y2)));
491 fXorOps.push_back(cmd.get());
492 cmd.release();
493 } catch (const std::exception &) {
494 throw;
495 }
496}
497
498//______________________________________________________________________________
500{
501 try {
502 std::unique_ptr<DrawLineXor> cmd(new DrawLineXor(windowID, Point(x1, y1), Point(x2, y2)));
503 fXorOps.push_back(cmd.get());
504 cmd.release();
505 } catch (const std::exception &) {
506 throw;
507 }
508}
509
510//______________________________________________________________________________
512{
513 assert(impl != 0 && "Flush, impl parameter is null");
514
515 //Basic es-guarantee: state is unknown, but valid, no
516 //resource leaks, no locked focus.
517
518 //All magic is here.
519 CGContextRef prevContext = 0;
520 CGContextRef currContext = 0;
521 QuartzView *prevView = nil;
522
523 for (size_type i = 0, e = fCommands.size(); i < e; ++i) {
524 const Command *cmd = fCommands[i];
525 if (!cmd)//Command was deleted by RemoveOperation/RemoveGraphicsOperation.
526 continue;
527
528 NSObject<X11Drawable> *drawable = impl->GetDrawable(cmd->fID);
529 if (drawable.fIsPixmap) {
530 cmd->Execute();//Can throw, ok.
531 continue;
532 }
533
534 QuartzView *view = (QuartzView *)impl->GetWindow(cmd->fID).fContentView;
535
536 if (prevView != view)
537 ClipOverlaps(view);//Can throw, ok.
538
539 prevView = view;
540
541 try {
542 if ([view lockFocusIfCanDraw]) {
543 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
544 assert(nsContext != nil && "Flush, currentContext is nil");
545 currContext = (CGContextRef)[nsContext graphicsPort];
546 assert(currContext != 0 && "Flush, graphicsPort is null");//remove this assert?
547
548 view.fContext = currContext;
549 if (prevContext && prevContext != currContext)
550 CGContextFlush(prevContext);
551 prevContext = currContext;
552
553 const Quartz::CGStateGuard ctxGuard(currContext);
554
555 //Clip regions first.
556 if (fClippedRegion.size())
557 CGContextClipToRects(currContext, &fClippedRegion[0], fClippedRegion.size());
558
559 //Now add also shape combine mask.
561 ClipToShapeMask(view, currContext);
562
563 cmd->Execute();//This can throw, we should restore as much as we can here.
564
565 if (view.fBackBuffer) {
566 //Very "special" window.
567 const Rectangle copyArea(0, 0, view.fBackBuffer.fWidth, view.fBackBuffer.fHeight);
568 [view copy : view.fBackBuffer area : copyArea
569 withMask : nil clipOrigin : Point() toPoint : Point()];
570 }
571
572 [view unlockFocus];
573
574 view.fContext = 0;
575 }
576 } catch (const std::exception &) {
577 //Focus was locked, roll-back:
578 [view unlockFocus];
579 //View's context was modified, roll-back:
580 view.fContext = 0;
581 //Re-throw, something really bad happened (std::bad_alloc).
582 throw;
583 }
584 }
585
586 if (currContext)
587 CGContextFlush(currContext);
588
590}
591
592//______________________________________________________________________________
594{
595 // The only XOR operations we ever had to support was drawing
596 // lines of a crosshair in a TCanvas. We were using a deprecated
597 // (since 10.14) trick with locking a focus on a view, drawing,
598 // flushing CGContext and then unlocking. This is not working
599 // starting from 10.15. So now the only thing we do - we draw
600 // a crosshair into the special transparent window which is
601 // attached on top of the canvas.
602 assert(impl != 0 && "FlushXOROps, impl parameter is null");
603
604 if (fXorOps.size() < 2) {
606 return;
607 }
608
609 NSObject<X11Drawable> * const drawable = impl->GetDrawable(fXorOps.back()->fID);
610 assert([drawable isKindOfClass : [QuartzView class]] &&
611 "FlushXOROps, drawable must be of type QuartzView");
612 QuartzView * const view = (QuartzView *)drawable;
613 QuartzWindow * const window = view.fQuartzWindow;
614 auto crosshairWindow = [window findCrosshairWindow];
615 if (!crosshairWindow) {
616 ::Warning("FlushXOROps", "No CrosshairWindow found to draw into");
618 return;
619 }
620
621 for (auto *candidateOp : fXorOps) {
622 if (!dynamic_cast<DrawLineXor *>(candidateOp)) {
623 NSLog(@"XOR mode supports DrawLine only, unexpected operation was found");
625 return;
626 }
627 }
628
629 // If size is > 2, we take the last two operations.
630 DrawLineXor *line1 = static_cast<DrawLineXor *>(*(fXorOps.end() - 2));
631 DrawLineXor *line2 = static_cast<DrawLineXor *>(fXorOps.back());
632
633 auto rootToNs = [](Point rp) {
634 return NSPoint{CGFloat(rp.fX), CGFloat(rp.fY)};
635 };
636
637 NSPoint cross[] = {rootToNs(line1->start()), rootToNs(line1->end()),
638 rootToNs(line2->start()), rootToNs(line2->end())};
639
640 for (auto &point : cross) {
641 // From the view's coordinates to window's:
642 point = [view convertPoint : point toView : nil];
643 }
644
645 CrosshairView *cv = (CrosshairView *)crosshairWindow.contentView;
646 cv.start1 = cross[0];
647 cv.end1 = cross[1];
648 cv.start2 = cross[2];
649 cv.end2 = cross[3];
650 [cv setNeedsDisplay : YES];
651
653}
654
655//______________________________________________________________________________
657{
658 for (size_type i = 0; i < fCommands.size(); ++i) {
659 if (fCommands[i] && fCommands[i]->HasOperand(drawable)) {
660 delete fCommands[i];
661 fCommands[i] = 0;
662 }
663 }
664
665 for (size_type i = 0; i < fXorOps.size(); ++i) {
666 if (fXorOps[i] && fXorOps[i]->HasOperand(drawable)) {
667 delete fXorOps[i];
668 fXorOps[i] = 0;
669 }
670 }
671}
672
673//______________________________________________________________________________
675{
676 for (size_type i = 0; i < fCommands.size(); ++i) {
677 if (fCommands[i] && fCommands[i]->HasOperand(wid) &&
678 fCommands[i]->IsGraphicsCommand())
679 {
680 delete fCommands[i];
681 fCommands[i] = 0;
682 }
683 }
684}
685
686//______________________________________________________________________________
688{
689 for (size_type i = 0; i < fCommands.size(); ++i) {
690 if (fXorOps[i] && fXorOps[i]->HasOperand(wid)) {
691 delete fXorOps[i];
692 fXorOps[i] = 0;
693 }
694 }
695}
696
697//______________________________________________________________________________
699{
700 for (size_type i = 0, e = fCommands.size(); i < e; ++i)
701 delete fCommands[i];
702
703 fCommands.clear();
704}
705
706//______________________________________________________________________________
708{
709 for (size_type i = 0, e = fXorOps.size(); i < e; ++i)
710 delete fXorOps[i];
711
712 fXorOps.clear();
713}
714
715//Clipping machinery.
716
717namespace {
718
719//________________________________________________________________________________________
720bool RectsOverlap(const NSRect &r1, const NSRect &r2)
721{
722 if (r2.origin.x >= r1.origin.x + r1.size.width)
723 return false;
724 if (r2.origin.x + r2.size.width <= r1.origin.x)
725 return false;
726 if (r2.origin.y >= r1.origin.y + r1.size.height)
727 return false;
728 if (r2.origin.y + r2.size.height <= r1.origin.y)
729 return false;
730
731 return true;
732}
733
734}
735
736//______________________________________________________________________________
738{
739 //QuartzViews do not have backing store.
740 //But ROOT calls gClient->NeedRedraw ignoring
741 //children or overlapping siblings. This leads
742 //to obvious problems, for example, parent
743 //erasing every child inside while repainting itself.
744 //To fix this and emulate window with backing store
745 //without real backing store, I'm calculating the
746 //area of a view this is visible and not overlapped.
747
748 //Who can overlap our view?
749 //1. Its own siblings and, probably, siblings of its ancestors.
750 //2. Children views.
751
752 assert(view != nil && "ClipOverlaps, view parameter is nil");
753
754 typedef std::vector<QuartzView *>::reverse_iterator reverse_iterator;
755 typedef std::vector<CGRect>::iterator rect_iterator;
756
757 fRectsToClip.clear();
758 fClippedRegion.clear();
759
760 //Check siblings and ancestors' siblings:
761
762 //1. Remember the whole branch starting from our view
763 //up to a top-level window.
764 fViewBranch.clear();
765 for (QuartzView *v = view; v; v = v.fParentView)
766 fViewBranch.push_back(v);
767
768 //We do not need content view, since it does not have any siblings.
769 if (fViewBranch.size())
770 fViewBranch.pop_back();
771
772 //For every fViewBranch[i] in our branch, we're looking for overlapping siblings.
773 //Calculations are in view.fParentView's coordinate system.
774
775 WidgetRect clipRect;
776 NSRect frame1 = {};
777
778 const NSRect frame2 = view.frame;
779
780 for (reverse_iterator it = fViewBranch.rbegin(), eIt = fViewBranch.rend(); it != eIt; ++it) {
781 QuartzView *ancestorView = *it;//This is either one of ancestors, or a view itself.
782 bool doCheck = false;
783 for (QuartzView *sibling in [ancestorView.fParentView subviews]) {
784 if (ancestorView == sibling) {
785 //View has its children in an array, and for every subviews[i] in this array,
786 //only views with index > i can overlap subviews[i].
787 doCheck = true;//all views after this must be checked.
788 continue;
789 } else if (!doCheck || sibling.fMapState != kIsViewable) {
790 continue;
791 }
792
793 frame1 = sibling.frame;
794
795 if (!frame1.size.width || !frame1.size.height)
796 continue;
797
798 frame1.origin = [sibling.fParentView convertPoint : frame1.origin
799 toView : view.fParentView];
800
801 //Check if two rects intersect.
802 if (RectsOverlap(frame2, frame1)) {
803 //Substruct frame1 from our view's rect.
804 clipRect.fX1 = frame1.origin.x;
805 clipRect.fX2 = clipRect.fX1 + frame1.size.width;
806 clipRect.fY1 = frame1.origin.y;
807 clipRect.fY2 = clipRect.fY1 + frame1.size.height;
808 fRectsToClip.push_back(clipRect);
809 }
810 }
811 }
812
813 //Substruct children.
814
815 for (QuartzView *child in [view subviews]) {
816 if (child.fMapState != kIsViewable)
817 continue;
818
819 frame1 = child.frame;
820
821 if (!frame1.size.width || !frame1.size.height)
822 continue;
823
824 if (view.fParentView)//view can also be a content view.
825 frame1.origin = [view convertPoint : frame1.origin toView : view.fParentView];
826
827 if (RectsOverlap(frame2, frame1)) {
828 clipRect.fX1 = frame1.origin.x;
829 clipRect.fX2 = clipRect.fX1 + frame1.size.width;
830 clipRect.fY1 = frame1.origin.y;
831 clipRect.fY2 = clipRect.fY1 + frame1.size.height;
832 fRectsToClip.push_back(clipRect);
833 }
834 }
835
836 if (fRectsToClip.size()) {
837 //Now, if we have any rectanges to substruct them from our view's frame,
838 //we are building a set of rectangles, which represents visible part of view.
839
840 WidgetRect rect(frame2.origin.x, frame2.origin.y, frame2.origin.x + frame2.size.width,
841 frame2.origin.y + frame2.size.height);
842
843 BuildClipRegion(rect);
844
845 if (view.fParentView) {
846 //To able to use this set of rectangles with CGContextClipToRects,
847 //convert them (if needed) into view's own coordinate system.
848 rect_iterator recIt = fClippedRegion.begin(), eIt = fClippedRegion.end();
849 for (; recIt != eIt; ++recIt) {
850 if (!recIt->size.width && !recIt->size.height) {
851 //This is a special 'empty' rectangle, which means our view is completely hidden.
852 assert(fClippedRegion.size() == 1 && "ClipOverlaps, internal logic error");
853 break;
854 }
855 recIt->origin = NSPointToCGPoint([view.fParentView convertPoint :
856 NSPointFromCGPoint(recIt->origin) toView : view]);
857 }
858 }
859 }
860}
861
862namespace {
863
864typedef std::vector<int>::iterator int_iterator;
865
866//_____________________________________________________________________________________________________
867int_iterator BinarySearchLeft(int_iterator first, int_iterator last, int value)
868{
869 if (first == last)
870 return last;
871
872 const int_iterator it = std::lower_bound(first, last, value);
873 assert(it != last && (it == first || *it == value) && "internal logic error");
874
875 //If value < *first, return last (not found).
876 return it == first && *it != value ? last : it;
877}
878
879//_____________________________________________________________________________________________________
880int_iterator BinarySearchRight(int_iterator first, int_iterator last, int value)
881{
882 if (first == last)
883 return last;
884
885 const int_iterator it = std::lower_bound(first, last, value);
886 assert((it == last || *it == value) && "internal logic error");
887
888 return it;
889}
890
891}//unnamed namespace.
892
893//_____________________________________________________________________________________________________
895{
896 //Input requirements:
897 // 1) all rects are valid (non-empty and x1 < x2, y1 < y2);
898 // 2) all rects intersect with widget's rect.
899 //I do not check these conditions here, this is done when filling rectsToClip.
900
901 //I did not find any reasonable algorithm (have to search better?),
902 //code in gdk and pixman has to many dependencies and is lib-specific +
903 //they require input to be quite special:
904 // a) no overlaps (in my case I have overlaps)
905 // b) sorted in a special way.
906 //To convert my input into such a format
907 //means to implement everything myself (for example, to work out overlaps).
908
909 //Also, my case is more simple: gdk and pixman substract region (== set of rectangles)
910 //from another region, I have to substract region from _one_ rectangle.
911
912 //This is quite straightforward implementation - I'm calculation rectangles, which are part of
913 //a widget's rect, not hidden by any of fRectsToClip.
914
915 typedef std::vector<WidgetRect>::const_iterator rect_const_iterator;
916
917 assert(fRectsToClip.size() != 0 && "BuildClipRegion, nothing to clip");
918
919 fClippedRegion.clear();
920 fXBounds.clear();
921 fYBounds.clear();
922
923 //[First, we "cut" the original rect into stripes.
924 rect_const_iterator recIt = fRectsToClip.begin(), endIt = fRectsToClip.end();
925 for (; recIt != endIt; ++recIt) {
926 if (recIt->fX1 <= rect.fX1 && recIt->fX2 >= rect.fX2 &&
927 recIt->fY1 <= rect.fY1 && recIt->fY2 >= rect.fY2) {
928 //this rect completely overlaps our view, not need to calculate anything at all.
929 fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));
930 return;
931 }
932
933 if (recIt->fX1 > rect.fX1)//recIt->x1 is always < rect.x2 (input validation).
934 fXBounds.push_back(recIt->fX1);
935
936 if (recIt->fX2 < rect.fX2)//recIt->x2 is always > rect.x1 (input validation).
937 fXBounds.push_back(recIt->fX2);
938
939 if (recIt->fY1 > rect.fY1)
940 fYBounds.push_back(recIt->fY1);
941
942 if (recIt->fY2 < rect.fY2)
943 fYBounds.push_back(recIt->fY2);
944 }
945
946 std::sort(fXBounds.begin(), fXBounds.end());
947 std::sort(fYBounds.begin(), fYBounds.end());
948
949 //We do not need duplicates.
950 const int_iterator xBoundsEnd = std::unique(fXBounds.begin(), fXBounds.end());
951 const int_iterator yBoundsEnd = std::unique(fYBounds.begin(), fYBounds.end());
952 //Rectangle is now "cut into pieces"].
953
954 const size_type nXBands = size_type(xBoundsEnd - fXBounds.begin()) + 1;
955 const size_type nYBands = size_type(yBoundsEnd - fYBounds.begin()) + 1;
956
957 fGrid.assign(nXBands * nYBands, false);
958
959 //Mark the overlapped parts.
960 recIt = fRectsToClip.begin(), endIt = fRectsToClip.end();
961 for (; recIt != endIt; ++recIt) {
962 const int_iterator left = BinarySearchLeft(fXBounds.begin(), xBoundsEnd, recIt->fX1);
963 const size_type firstXBand = left == xBoundsEnd ? 0 : left - fXBounds.begin() + 1;
964
965 const int_iterator right = BinarySearchRight(fXBounds.begin(), xBoundsEnd, recIt->fX2);
966 const size_type lastXBand = right - fXBounds.begin() + 1;
967
968 const int_iterator bottom = BinarySearchLeft(fYBounds.begin(), yBoundsEnd, recIt->fY1);
969 const size_type firstYBand = bottom == yBoundsEnd ? 0 : bottom - fYBounds.begin() + 1;
970
971 const int_iterator top = BinarySearchRight(fYBounds.begin(), yBoundsEnd, recIt->fY2);
972 const size_type lastYBand = top - fYBounds.begin() + 1;
973
974 for (size_type i = firstYBand; i < lastYBand; ++i) {
975 const size_type baseIndex = i * nXBands;
976 for (size_type j = firstXBand; j < lastXBand; ++j)
977 fGrid[baseIndex + j] = true;
978 }
979 }
980
981 //I do not merge rectangles.
982 //Search for non-overlapped parts and create rectangles for them.
983 CGRect newRect = {};
984
985 for (size_type i = 0; i < nYBands; ++i) {
986 const size_type baseIndex = i * nXBands;
987 for (size_type j = 0; j < nXBands; ++j) {
988 if (!fGrid[baseIndex + j]) {
989 newRect.origin.x = j ? fXBounds[j - 1] : rect.fX1;
990 newRect.origin.y = i ? fYBounds[i - 1] : rect.fY1;
991
992 newRect.size.width = (j == nXBands - 1 ? rect.fX2 : fXBounds[j]) - newRect.origin.x;
993 newRect.size.height = (i == nYBands - 1 ? rect.fY2 : fYBounds[i]) - newRect.origin.y;
994
995 fClippedRegion.push_back(newRect);
996 }
997 }
998 }
999
1000 if (!fClippedRegion.size())//Completely hidden
1001 fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));
1002}
1003
1004}//X11
1005}//MacOSX
1006}//ROOT
Handle_t Pixmap_t
Definition: GuiTypes.h:29
Handle_t Drawable_t
Definition: GuiTypes.h:30
@ kIsViewable
Definition: GuiTypes.h:45
Handle_t Window_t
Definition: GuiTypes.h:28
ROOT::R::TRInterface & r
Definition: Object.C:4
#define h(i)
Definition: RSha256.hxx:106
#define e(i)
Definition: RSha256.hxx:103
static const double x2[5]
static const double x1[5]
unsigned short UShort_t
Definition: RtypesCore.h:38
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
void Warning(const char *location, const char *msgfmt,...)
#define gVirtualX
Definition: TVirtualX.h:338
point * points
Definition: X3DBuffer.c:22
NSObject< X11Drawable > * GetDrawable(Drawable_t drawableD) const
NSObject< X11Window > * GetWindow(Window_t windowID) const
ClearArea(Window_t wid, const Rectangle_t &area)
Definition: X11Buffer.mm:111
const Rectangle_t fArea
Definition: X11Buffer.h:97
void RemoveXORGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:687
void AddDrawBoxXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:487
std::vector< WidgetRect > fRectsToClip
Definition: X11Buffer.h:302
std::vector< CGRect > fClippedRegion
Definition: X11Buffer.h:303
std::vector< Command * > fXorOps
Definition: X11Buffer.h:245
std::vector< bool > fGrid
Definition: X11Buffer.h:306
void AddDrawLineXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:499
void Flush(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:511
void AddDrawSegments(Drawable_t wid, const GCValues_t &gc, const Segment_t *segments, Int_t nSegments)
Definition: X11Buffer.mm:340
void AddFillPolygon(Drawable_t wid, const GCValues_t &gc, const Point_t *polygon, Int_t nPoints)
Definition: X11Buffer.mm:445
void FlushXOROps(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:593
void ClipOverlaps(QuartzView *view)
Definition: X11Buffer.mm:737
std::vector< QuartzView * > fViewBranch
Definition: X11Buffer.h:243
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:674
void AddClearArea(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:356
std::vector< int > fYBounds
Definition: X11Buffer.h:305
void AddDrawRectangle(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:427
void AddDrawLine(Drawable_t wid, const GCValues_t &gc, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:326
void RemoveOperationsForDrawable(Drawable_t wid)
Definition: X11Buffer.mm:656
std::vector< Command * >::size_type size_type
Definition: X11Buffer.h:247
void AddDrawString(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, const char *text, Int_t len)
Definition: X11Buffer.mm:393
void AddDeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:475
std::vector< Command * > fCommands
Definition: X11Buffer.h:242
std::vector< int > fXBounds
Definition: X11Buffer.h:304
void AddCopyArea(Drawable_t src, Drawable_t dst, const GCValues_t &gc, Int_t srcX, Int_t srcY, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
Definition: X11Buffer.mm:373
void AddUpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:461
void BuildClipRegion(const WidgetRect &rect)
Definition: X11Buffer.mm:894
void AddFillRectangle(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:409
const GCValues_t fGC
Definition: X11Buffer.h:50
Command(Drawable_t wid)
Definition: X11Buffer.mm:45
const Drawable_t fID
Definition: X11Buffer.h:49
virtual bool IsGraphicsCommand() const
Definition: X11Buffer.mm:68
virtual void Execute() const =0
virtual bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:62
bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:137
const Drawable_t fSrc
Definition: X11Buffer.h:110
CopyArea(Drawable_t src, Drawable_t dst, const GCValues_t &gc, const Rectangle_t &area, const Point &dstPoint)
Definition: X11Buffer.mm:127
const Rectangle_t fArea
Definition: X11Buffer.h:111
DeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:249
DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:264
DrawLineXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:294
DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:74
DrawRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:212
std::vector< Segment_t > fSegments
Definition: X11Buffer.h:84
DrawSegments(Drawable_t wid, const GCValues_t &gc, const Segment_t *segments, Int_t nSegments)
Definition: X11Buffer.mm:91
DrawString(Drawable_t wid, const GCValues_t &gc, const Point &point, const std::string &text)
Definition: X11Buffer.mm:154
const std::string fText
Definition: X11Buffer.h:130
std::vector< Point_t > fPolygon
Definition: X11Buffer.h:160
FillPolygon(Drawable_t wid, const GCValues_t &gc, const Point_t *points, Int_t nPoints)
Definition: X11Buffer.mm:192
const Rectangle_t fRectangle
Definition: X11Buffer.h:145
FillRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:173
UpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:231
This class implements TVirtualX interface for MacOS X, using Cocoa and Quartz 2D.
Definition: TGCocoa.h:58
void DrawLineAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: TGCocoa.mm:1672
void FillRectangleAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:1864
void CopyAreaAux(Drawable_t src, Drawable_t dst, const GCValues_t &gc, Int_t srcX, Int_t srcY, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
Definition: TGCocoa.mm:2074
void DrawRectangleAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:1795
void DrawStringAux(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, const char *s, Int_t len)
Definition: TGCocoa.mm:2148
void ClearAreaAux(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:2225
void DrawSegmentsAux(Drawable_t wid, const GCValues_t &gcVals, const Segment_t *segments, Int_t nSegments)
Definition: TGCocoa.mm:1749
TText * text
NSPoint end1
Definition: QuartzWindow.h:31
NSPoint start2
Definition: QuartzWindow.h:33
NSPoint end2
Definition: QuartzWindow.h:34
NSPoint start1
Definition: QuartzWindow.h:30
unsigned fHeight
Definition: QuartzPixmap.h:38
unsigned fWidth
Definition: QuartzPixmap.h:37
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:207
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:269
CGContextRef fContext
Definition: QuartzWindow.h:186
QuartzView * fParentView
Definition: QuartzWindow.h:196
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:63
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
void swap(RDirectoryEntry &e1, RDirectoryEntry &e2) noexcept
void ClipToShapeMask(NSView< X11Window > *view, CGContextRef ctx)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
Definition: first.py:1
Pixmap_t fClipMask
Definition: GuiTypes.h:246
Short_t fX
Definition: GuiTypes.h:361
UShort_t fHeight
Definition: GuiTypes.h:362
Short_t fY
Definition: GuiTypes.h:361
UShort_t fWidth
Definition: GuiTypes.h:362
lv DrawLine(0.33, 0.0, 0.33, 1.0)