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
32namespace ROOT {
33namespace MacOSX {
34namespace X11 {
35
36//______________________________________________________________________________
38 : fID(wid),
39 fGC(gc)
40{
41}
42
43//______________________________________________________________________________
45 : fID(wid),
46 fGC()
47{
48}
49
50//______________________________________________________________________________
52{
53}
54
55//______________________________________________________________________________
56void Command::Execute(CGContextRef /*ctx*/)const
57{
58}
59
60//______________________________________________________________________________
62{
63 return wid == fID;
64}
65
66//______________________________________________________________________________
68{
69 return false;
70}
71
72//______________________________________________________________________________
73DrawLine::DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
74 : Command(wid, gc),
75 fP1(p1),
76 fP2(p2)
77{
78}
79
80//______________________________________________________________________________
82{
83 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
84 "Execute, gVirtualX is either null or not of TGCocoa type");
85 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
86 vx->DrawLineAux(fID, fGC, fP1.fX, fP1.fY, fP2.fX, fP2.fY);
87}
88
89//______________________________________________________________________________
91 const Segment_t *segments, Int_t nSegments)
92 : Command(wid, gc)
93{
94 assert(segments != 0 && "DrawSegments, segments parameter is null");
95 assert(nSegments > 0 && "DrawSegments, nSegments <= 0");
96
97 fSegments.assign(segments, segments + nSegments);
98}
99
100//______________________________________________________________________________
102{
103 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
104 "Execute, gVirtualX is either null or not of TGCocoa type");
105 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
106 vx->DrawSegmentsAux(fID, fGC, &fSegments[0], (Int_t)fSegments.size());
107}
108
109//______________________________________________________________________________
111 : Command(wid),
112 fArea(area)
113{
114}
115
116//______________________________________________________________________________
118{
119 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
120 "Execute, gVirtualX is either null or not of TGCocoa type");
121 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
123}
124
125//______________________________________________________________________________
127 const Rectangle_t &area, const Point &dstPoint)
128 : Command(dst, gc),
129 fSrc(src),
130 fArea(area),
131 fDstPoint(dstPoint)
132{
133}
134
135//______________________________________________________________________________
137{
138 return fID == drawable || fSrc == drawable || fGC.fClipMask == drawable;
139}
140
141//______________________________________________________________________________
143{
144 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
145 "Execute, gVirtualX is either null or not of TGCocoa type");
146
147 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
150}
151
152//______________________________________________________________________________
154 const std::string &text)
155 : Command(wid, gc),
156 fPoint(point),
157 fText(text)
158{
159}
160
161//______________________________________________________________________________
163{
164 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
165 "Execute, gVirtualX is either null or not of TGCocoa type");
166
167 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
168 vx->DrawStringAux(fID, fGC, fPoint.fX, fPoint.fY, fText.c_str(), fText.length());
169}
170
171//______________________________________________________________________________
173 const Rectangle_t &rectangle)
174 : Command(wid, gc),
175 fRectangle(rectangle)
176{
177}
178
179//______________________________________________________________________________
181{
182 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
183 "Execute, gVirtualX is either null or not of TGCocoa type");
184
185 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
188}
189
190//______________________________________________________________________________
192 const Point_t *points, Int_t nPoints)
193 : Command(wid, gc)
194{
195 assert(points != 0 && "FillPolygon, points parameter is null");
196 assert(nPoints > 0 && "FillPolygon, nPoints <= 0");
197
198 fPolygon.assign(points, points + nPoints);
199}
200
201//______________________________________________________________________________
203{
204 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
205 "Execute, gVirtualX is either null or not of TGCocoa type");
206
207 ((TGCocoa *)gVirtualX)->FillPolygonAux(fID, fGC, &fPolygon[0], (Int_t)fPolygon.size());
208}
209
210//______________________________________________________________________________
212 const Rectangle_t &rectangle)
213 : Command(wid, gc),
214 fRectangle(rectangle)
215{
216}
217
218//______________________________________________________________________________
220{
221 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
222 "Execute, gVirtualX is either null or not of TGCocoa type");
223
224 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
227}
228
229//______________________________________________________________________________
231 : Command(view.fID),
232 fView(view)
233{
234 assert(view != nil && "UpdateWindow, view parameter is nil");//view.fID will be also 0.
235}
236
237//______________________________________________________________________________
239{
240 assert(fView.fContext != 0 && "Execute, view.fContext is null");
241
242 if (QuartzPixmap *pixmap = fView.fBackBuffer)
243 [fView copy : pixmap area : Rectangle(0, 0, pixmap.fWidth, pixmap.fHeight)
244 withMask : nil clipOrigin : Point() toPoint : Point()];
245}
246
247//______________________________________________________________________________
249 : Command(pixmap, GCValues_t())
250{
251}
252
253//______________________________________________________________________________
255{
256 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
257 "Execute, gVirtualX is either null or not of TGCocoa type");
258
259 ((TGCocoa *)gVirtualX)->DeletePixmapAux(fID);
260}
261
262//______________________________________________________________________________
263DrawBoxXor::DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
264 : Command(windowID, GCValues_t()),
265 fP1(p1),
266 fP2(p2)
267{
268 if (fP1.fX > fP2.fX)
270 if (fP1.fY > fP2.fY)
272}
273
274//______________________________________________________________________________
276{
277 //Noop.
278}
279
280//______________________________________________________________________________
281void DrawBoxXor::Execute(CGContextRef ctx)const
282{
283 //
284 assert(ctx != 0 && "Execute, ctx parameter is null");
285
286 CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
287 CGContextSetLineWidth(ctx, 1.);
288
289 CGContextStrokeRect(ctx, CGRectMake(fP1.fX, fP1.fY, fP2.fX - fP1.fX, fP2.fY - fP1.fY));
290}
291
292//______________________________________________________________________________
293DrawLineXor::DrawLineXor(Window_t windowID, const Point &p1, const Point &p2)
294 : Command(windowID, GCValues_t()),
295 fP1(p1),
296 fP2(p2)
297{
298}
299
300//______________________________________________________________________________
302{
303 //Noop.
304}
305
306//______________________________________________________________________________
307void DrawLineXor::Execute(CGContextRef ctx)const
308{
309 //
310 assert(ctx != 0 && "Execute, ctx parameter is null");
311
312 CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
313 CGContextSetLineWidth(ctx, 1.);
314
315 CGContextBeginPath(ctx);
316 CGContextMoveToPoint(ctx, fP1.fX, fP1.fY);
317 CGContextAddLineToPoint(ctx, fP2.fX, fP2.fY);
318 CGContextStrokePath(ctx);
319}
320
321//______________________________________________________________________________
323{
324}
325
326//______________________________________________________________________________
328{
331}
332
333//______________________________________________________________________________
335 Int_t y1, Int_t x2, Int_t y2)
336{
337 try {
338 //if this throws, I do not care.
339 std::unique_ptr<DrawLine> cmd(new DrawLine(wid, gc, Point(x1, y1), Point(x2, y2)));
340 fCommands.push_back(cmd.get());//this can throw.
341 cmd.release();
342 } catch (const std::exception &) {
343 throw;
344 }
345}
346
347//______________________________________________________________________________
349 const Segment_t *segments, Int_t nSegments)
350{
351 assert(segments != 0 && "AddDrawSegments, segments parameter is null");
352 assert(nSegments > 0 && "AddDrawSegments, nSegments <= 0");
353
354 try {
355 std::unique_ptr<DrawSegments> cmd(new DrawSegments(wid, gc, segments, nSegments));
356 fCommands.push_back(cmd.get());
357 cmd.release();
358 } catch (const std::exception &) {
359 throw;
360 }
361}
362
363//______________________________________________________________________________
365{
366 try {
367 Rectangle_t r = {};//To be replaced with X11::Rectangle.
368 r.fX = x;
369 r.fY = y;
370 r.fWidth = (UShort_t)w;
371 r.fHeight = (UShort_t)h;
372 std::unique_ptr<ClearArea> cmd(new ClearArea(wid, r));//Can throw, nothing leaks.
373 fCommands.push_back(cmd.get());//this can throw.
374 cmd.release();
375 } catch (const std::exception &) {
376 throw;
377 }
378}
379
380//______________________________________________________________________________
382 Int_t srcX, Int_t srcY, UInt_t width, UInt_t height,
383 Int_t dstX, Int_t dstY)
384{
385 try {
386 Rectangle_t area = {};
387 area.fX = srcX;
388 area.fY = srcY;
389 area.fWidth = (UShort_t)width;
390 area.fHeight = (UShort_t)height;
391 //Can throw, nothing leaks.
392 std::unique_ptr<CopyArea> cmd(new CopyArea(src, dst, gc, area, Point(dstX, dstY)));
393 fCommands.push_back(cmd.get());//this can throw.
394 cmd.release();
395 } catch (const std::exception &) {
396 throw;
397 }
398}
399
400//______________________________________________________________________________
402 const char *text, Int_t len)
403{
404 try {
405 if (len < 0)//Negative length can come from caller.
406 len = std::strlen(text);
407 const std::string substr(text, len);//Can throw.
408 std::unique_ptr<DrawString> cmd(new DrawString(wid, gc, Point(x, y), substr));//Can throw.
409 fCommands.push_back(cmd.get());//can throw.
410 cmd.release();
411 } catch (const std::exception &) {
412 throw;
413 }
414}
415
416//______________________________________________________________________________
418 Int_t x, Int_t y, UInt_t w, UInt_t h)
419{
420 try {
421 Rectangle_t r = {};
422 r.fX = x;
423 r.fY = y;
424 r.fWidth = (UShort_t)w;
425 r.fHeight = (UShort_t)h;
426 std::unique_ptr<FillRectangle> cmd(new FillRectangle(wid, gc, r));
427 fCommands.push_back(cmd.get());
428 cmd.release();
429 } catch (const std::exception &) {
430 throw;
431 }
432}
433
434//______________________________________________________________________________
436 Int_t x, Int_t y, UInt_t w, UInt_t h)
437{
438 try {
439 Rectangle_t r = {};
440 r.fX = x;
441 r.fY = y;
442 r.fWidth = (UShort_t)w;
443 r.fHeight = (UShort_t)h;
444 std::unique_ptr<DrawRectangle> cmd(new DrawRectangle(wid, gc, r));
445 fCommands.push_back(cmd.get());
446 cmd.release();
447 } catch (const std::exception &) {
448 throw;
449 }
450}
451
452//______________________________________________________________________________
454 const Point_t *polygon, Int_t nPoints)
455{
456 assert(polygon != 0 && "AddFillPolygon, polygon parameter is null");
457 assert(nPoints > 0 && "AddFillPolygon, nPoints <= 0");
458
459 try {
460 std::unique_ptr<FillPolygon> cmd(new FillPolygon(wid, gc, polygon, nPoints));
461 fCommands.push_back(cmd.get());
462 cmd.release();
463 } catch (const std::exception &) {
464 throw;
465 }
466}
467
468//______________________________________________________________________________
470{
471 assert(view != nil && "AddUpdateWindow, view parameter is nil");
472
473 try {
474 std::unique_ptr<UpdateWindow> cmd(new UpdateWindow(view));
475 fCommands.push_back(cmd.get());
476 cmd.release();
477 } catch (const std::exception &) {
478 throw;
479 }
480}
481
482//______________________________________________________________________________
484{
485 try {
486 std::unique_ptr<DeletePixmap> cmd(new DeletePixmap(pixmapID));
487 fCommands.push_back(cmd.get());
488 cmd.release();
489 } catch (const std::exception &) {
490 throw;
491 }
492}
493
494//______________________________________________________________________________
496{
497 try {
498 std::unique_ptr<DrawBoxXor> cmd(new DrawBoxXor(windowID, Point(x1, y1), Point(x2, y2)));
499 fXorOps.push_back(cmd.get());
500 cmd.release();
501 } catch (const std::exception &) {
502 throw;
503 }
504}
505
506//______________________________________________________________________________
508{
509 try {
510 std::unique_ptr<DrawLineXor> cmd(new DrawLineXor(windowID, Point(x1, y1), Point(x2, y2)));
511 fXorOps.push_back(cmd.get());
512 cmd.release();
513 } catch (const std::exception &) {
514 throw;
515 }
516}
517
518//______________________________________________________________________________
520{
521 assert(impl != 0 && "Flush, impl parameter is null");
522
523 //Basic es-guarantee: state is unknown, but valid, no
524 //resource leaks, no locked focus.
525
526 //All magic is here.
527 CGContextRef prevContext = 0;
528 CGContextRef currContext = 0;
529 QuartzView *prevView = nil;
530
531 for (size_type i = 0, e = fCommands.size(); i < e; ++i) {
532 const Command *cmd = fCommands[i];
533 if (!cmd)//Command was deleted by RemoveOperation/RemoveGraphicsOperation.
534 continue;
535
536 NSObject<X11Drawable> *drawable = impl->GetDrawable(cmd->fID);
537 if (drawable.fIsPixmap) {
538 cmd->Execute();//Can throw, ok.
539 continue;
540 }
541
542 QuartzView *view = (QuartzView *)impl->GetWindow(cmd->fID).fContentView;
543
544 if (prevView != view)
545 ClipOverlaps(view);//Can throw, ok.
546
547 prevView = view;
548
549 try {
550 if ([view lockFocusIfCanDraw]) {
551 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
552 assert(nsContext != nil && "Flush, currentContext is nil");
553 currContext = (CGContextRef)[nsContext graphicsPort];
554 assert(currContext != 0 && "Flush, graphicsPort is null");//remove this assert?
555
556 view.fContext = currContext;
557 if (prevContext && prevContext != currContext)
558 CGContextFlush(prevContext);
559 prevContext = currContext;
560
561 const Quartz::CGStateGuard ctxGuard(currContext);
562
563 //Clip regions first.
564 if (fClippedRegion.size())
565 CGContextClipToRects(currContext, &fClippedRegion[0], fClippedRegion.size());
566
567 //Now add also shape combine mask.
569 ClipToShapeMask(view, currContext);
570
571 cmd->Execute();//This can throw, we should restore as much as we can here.
572
573 if (view.fBackBuffer) {
574 //Very "special" window.
575 const Rectangle copyArea(0, 0, view.fBackBuffer.fWidth, view.fBackBuffer.fHeight);
576 [view copy : view.fBackBuffer area : copyArea
577 withMask : nil clipOrigin : Point() toPoint : Point()];
578 }
579
580 [view unlockFocus];
581
582 view.fContext = 0;
583 }
584 } catch (const std::exception &) {
585 //Focus was locked, roll-back:
586 [view unlockFocus];
587 //View's context was modified, roll-back:
588 view.fContext = 0;
589 //Re-throw, something really bad happened (std::bad_alloc).
590 throw;
591 }
592 }
593
594 if (currContext)
595 CGContextFlush(currContext);
596
598}
599
600//______________________________________________________________________________
602{
603 assert(impl != 0 && "FlushXOROps, impl parameter is null");
604
605 if (!fXorOps.size())
606 return;
607
608 //I assume here, that all XOR ops in one iteration (one Update call) must
609 //be for the same window (if not, there is no normal way to implement this at all).
610
611 NSObject<X11Drawable> *drawable = impl->GetDrawable(fXorOps[0]->fID);
612
613 assert([drawable isKindOfClass : [QuartzView class]] &&
614 "FlushXOROps, drawable must be of type QuartzView");
615
616 QuartzView *view = (QuartzView *)drawable;
617
618 if ([view lockFocusIfCanDraw]) {
619 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
620 assert(nsContext != nil && "FlushXOROps, currentContext is nil");
621 CGContextRef currContext = (CGContextRef)[nsContext graphicsPort];
622 assert(currContext != 0 && "FlushXOROps, graphicsPort is null");//remove this assert?
623
624 const Quartz::CGStateGuard ctxGuard(currContext);//ctx guard.
625
626 CGContextSetAllowsAntialiasing(currContext, false);
627
628 view.fContext = currContext;
629
630 if (view.fBackBuffer) {//back buffer has canvas' contents.
631 //Very "special" window.
632 const Rectangle copyArea(0, 0, view.fBackBuffer.fWidth, view.fBackBuffer.fHeight);
633 [view copy : view.fBackBuffer area : copyArea
634 withMask : nil clipOrigin : Point() toPoint : Point()];
635 }
636
637 //Now, do "XOR" drawings.
638 for (size_type i = 0, e = fXorOps.size(); i < e; ++i) {
639 if (fXorOps[i]) {
640 fXorOps[i]->Execute(currContext);
641 }
642 }
643
644 [view unlockFocus];
645 view.fContext = 0;
646
647 CGContextFlush(currContext);
648
649 CGContextSetAllowsAntialiasing(currContext, true);
650 }
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:36
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
#define gVirtualX
Definition: TVirtualX.h:345
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:110
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:495
std::vector< WidgetRect > fRectsToClip
Definition: X11Buffer.h:300
std::vector< CGRect > fClippedRegion
Definition: X11Buffer.h:301
std::vector< Command * > fXorOps
Definition: X11Buffer.h:242
std::vector< bool > fGrid
Definition: X11Buffer.h:304
void AddDrawLineXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:507
void Flush(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:519
void AddDrawSegments(Drawable_t wid, const GCValues_t &gc, const Segment_t *segments, Int_t nSegments)
Definition: X11Buffer.mm:348
void AddFillPolygon(Drawable_t wid, const GCValues_t &gc, const Point_t *polygon, Int_t nPoints)
Definition: X11Buffer.mm:453
void FlushXOROps(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:601
void ClipOverlaps(QuartzView *view)
Definition: X11Buffer.mm:737
std::vector< QuartzView * > fViewBranch
Definition: X11Buffer.h:240
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:364
std::vector< int > fYBounds
Definition: X11Buffer.h:303
void AddDrawRectangle(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:435
void AddDrawLine(Drawable_t wid, const GCValues_t &gc, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:334
void RemoveOperationsForDrawable(Drawable_t wid)
Definition: X11Buffer.mm:656
std::vector< Command * >::size_type size_type
Definition: X11Buffer.h:244
void AddDrawString(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, const char *text, Int_t len)
Definition: X11Buffer.mm:401
void AddDeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:483
std::vector< Command * > fCommands
Definition: X11Buffer.h:239
std::vector< int > fXBounds
Definition: X11Buffer.h:302
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:381
void AddUpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:469
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:417
const GCValues_t fGC
Definition: X11Buffer.h:50
Command(Drawable_t wid)
Definition: X11Buffer.mm:44
const Drawable_t fID
Definition: X11Buffer.h:49
virtual bool IsGraphicsCommand() const
Definition: X11Buffer.mm:67
virtual void Execute() const =0
virtual bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:61
bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:136
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:126
const Rectangle_t fArea
Definition: X11Buffer.h:111
DeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:248
DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:263
DrawLineXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:293
DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:73
DrawRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:211
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:90
DrawString(Drawable_t wid, const GCValues_t &gc, const Point &point, const std::string &text)
Definition: X11Buffer.mm:153
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:191
const Rectangle_t fRectangle
Definition: X11Buffer.h:145
FillRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:172
UpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:230
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
unsigned fHeight
Definition: QuartzPixmap.h:38
unsigned fWidth
Definition: QuartzPixmap.h:37
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:176
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:238
CGContextRef fContext
Definition: QuartzWindow.h:155
QuartzView * fParentView
Definition: QuartzWindow.h:165
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:38
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)
VSD Structures.
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)