19 #include <Cocoa/Cocoa.h>
37 Command::Command(Drawable_t wid,
const GCValues_t &gc)
44 Command::Command(Drawable_t wid)
56 void Command::Execute(CGContextRef )
const
61 bool Command::HasOperand(Drawable_t wid)
const
67 bool Command::IsGraphicsCommand()
const
73 DrawLine::DrawLine(Drawable_t wid,
const GCValues_t &gc,
const Point &p1,
const Point &p2)
81 void DrawLine::Execute()
const
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);
90 DrawSegments::DrawSegments(Drawable_t wid,
const GCValues_t &gc,
91 const Segment_t *segments, Int_t nSegments)
94 assert(segments != 0 &&
"DrawSegments, segments parameter is null");
95 assert(nSegments > 0 &&
"DrawSegments, nSegments <= 0");
97 fSegments.assign(segments, segments + nSegments);
101 void DrawSegments::Execute()
const
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());
110 ClearArea::ClearArea(Window_t wid,
const Rectangle_t &area)
117 void ClearArea::Execute()
const
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);
122 vx->ClearAreaAux(fID, fArea.fX, fArea.fY, fArea.fWidth, fArea.fHeight);
126 CopyArea::CopyArea(Drawable_t src, Drawable_t dst,
const GCValues_t &gc,
127 const Rectangle_t &area,
const Point &dstPoint)
136 bool CopyArea::HasOperand(Drawable_t drawable)
const
138 return fID == drawable || fSrc == drawable || fGC.fClipMask == drawable;
142 void CopyArea::Execute()
const
144 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
145 "Execute, gVirtualX is either null or not of TGCocoa type");
147 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
148 vx->CopyAreaAux(fSrc, fID, fGC, fArea.fX, fArea.fY, fArea.fWidth,
149 fArea.fHeight, fDstPoint.fX, fDstPoint.fY);
153 DrawString::DrawString(Drawable_t wid,
const GCValues_t &gc,
const Point &point,
154 const std::string &text)
162 void DrawString::Execute()
const
164 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
165 "Execute, gVirtualX is either null or not of TGCocoa type");
167 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
168 vx->DrawStringAux(fID, fGC, fPoint.fX, fPoint.fY, fText.c_str(), fText.length());
172 FillRectangle::FillRectangle(Drawable_t wid,
const GCValues_t &gc,
173 const Rectangle_t &rectangle)
175 fRectangle(rectangle)
180 void FillRectangle::Execute()
const
182 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
183 "Execute, gVirtualX is either null or not of TGCocoa type");
185 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
186 vx->FillRectangleAux(fID, fGC, fRectangle.fX, fRectangle.fY,
187 fRectangle.fWidth, fRectangle.fHeight);
191 FillPolygon::FillPolygon(Drawable_t wid,
const GCValues_t &gc,
192 const Point_t *points, Int_t nPoints)
195 assert(points != 0 &&
"FillPolygon, points parameter is null");
196 assert(nPoints > 0 &&
"FillPolygon, nPoints <= 0");
198 fPolygon.assign(points, points + nPoints);
202 void FillPolygon::Execute()
const
204 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
205 "Execute, gVirtualX is either null or not of TGCocoa type");
207 ((TGCocoa *)gVirtualX)->FillPolygonAux(fID, fGC, &fPolygon[0], (Int_t)fPolygon.size());
211 DrawRectangle::DrawRectangle(Drawable_t wid,
const GCValues_t &gc,
212 const Rectangle_t &rectangle)
214 fRectangle(rectangle)
219 void DrawRectangle::Execute()
const
221 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
222 "Execute, gVirtualX is either null or not of TGCocoa type");
224 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
225 vx->DrawRectangleAux(fID, fGC, fRectangle.fX, fRectangle.fY,
226 fRectangle.fWidth, fRectangle.fHeight);
230 UpdateWindow::UpdateWindow(QuartzView *view)
234 assert(view != nil &&
"UpdateWindow, view parameter is nil");
238 void UpdateWindow::Execute()
const
240 assert(fView.fContext != 0 &&
"Execute, view.fContext is null");
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()];
248 DeletePixmap::DeletePixmap(Pixmap_t pixmap)
249 : Command(pixmap, GCValues_t())
254 void DeletePixmap::Execute()
const
256 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
257 "Execute, gVirtualX is either null or not of TGCocoa type");
259 ((TGCocoa *)gVirtualX)->DeletePixmapAux(fID);
263 DrawBoxXor::DrawBoxXor(Window_t windowID,
const Point &p1,
const Point &p2)
264 : Command(windowID, GCValues_t()),
269 std::swap(fP1.fX, fP2.fX);
271 std::swap(fP1.fY, fP2.fY);
275 void DrawBoxXor::Execute()
const
281 void DrawBoxXor::Execute(CGContextRef ctx)
const
284 assert(ctx != 0 &&
"Execute, ctx parameter is null");
286 CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
287 CGContextSetLineWidth(ctx, 1.);
289 CGContextStrokeRect(ctx, CGRectMake(fP1.fX, fP1.fY, fP2.fX - fP1.fX, fP2.fY - fP1.fY));
293 DrawLineXor::DrawLineXor(Window_t windowID,
const Point &p1,
const Point &p2)
294 : Command(windowID, GCValues_t()),
301 void DrawLineXor::Execute()
const
307 void DrawLineXor::Execute(CGContextRef ctx)
const
310 assert(ctx != 0 &&
"Execute, ctx parameter is null");
312 CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
313 CGContextSetLineWidth(ctx, 1.);
315 CGContextBeginPath(ctx);
316 CGContextMoveToPoint(ctx, fP1.fX, fP1.fY);
317 CGContextAddLineToPoint(ctx, fP2.fX, fP2.fY);
318 CGContextStrokePath(ctx);
322 CommandBuffer::CommandBuffer()
327 CommandBuffer::~CommandBuffer()
330 ClearXOROperations();
334 void CommandBuffer::AddDrawLine(Drawable_t wid,
const GCValues_t &gc, Int_t x1,
335 Int_t y1, Int_t x2, Int_t y2)
339 std::unique_ptr<DrawLine> cmd(
new DrawLine(wid, gc, Point(x1, y1), Point(x2, y2)));
340 fCommands.push_back(cmd.get());
342 }
catch (
const std::exception &) {
348 void CommandBuffer::AddDrawSegments(Drawable_t wid,
const GCValues_t &gc,
349 const Segment_t *segments, Int_t nSegments)
351 assert(segments != 0 &&
"AddDrawSegments, segments parameter is null");
352 assert(nSegments > 0 &&
"AddDrawSegments, nSegments <= 0");
355 std::unique_ptr<DrawSegments> cmd(
new DrawSegments(wid, gc, segments, nSegments));
356 fCommands.push_back(cmd.get());
358 }
catch (
const std::exception &) {
364 void CommandBuffer::AddClearArea(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
370 r.fWidth = (UShort_t)w;
371 r.fHeight = (UShort_t)h;
372 std::unique_ptr<ClearArea> cmd(
new ClearArea(wid, r));
373 fCommands.push_back(cmd.get());
375 }
catch (
const std::exception &) {
381 void CommandBuffer::AddCopyArea(Drawable_t src, Drawable_t dst,
const GCValues_t &gc,
382 Int_t srcX, Int_t srcY, UInt_t width, UInt_t height,
383 Int_t dstX, Int_t dstY)
386 Rectangle_t area = {};
389 area.fWidth = (UShort_t)width;
390 area.fHeight = (UShort_t)height;
392 std::unique_ptr<CopyArea> cmd(
new CopyArea(src, dst, gc, area, Point(dstX, dstY)));
393 fCommands.push_back(cmd.get());
395 }
catch (
const std::exception &) {
401 void CommandBuffer::AddDrawString(Drawable_t wid,
const GCValues_t &gc, Int_t x, Int_t y,
402 const char *text, Int_t len)
406 len = std::strlen(text);
407 const std::string substr(text, len);
408 std::unique_ptr<DrawString> cmd(
new DrawString(wid, gc, Point(x, y), substr));
409 fCommands.push_back(cmd.get());
411 }
catch (
const std::exception &) {
417 void CommandBuffer::AddFillRectangle(Drawable_t wid,
const GCValues_t &gc,
418 Int_t x, Int_t y, UInt_t w, UInt_t h)
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());
429 }
catch (
const std::exception &) {
435 void CommandBuffer::AddDrawRectangle(Drawable_t wid,
const GCValues_t &gc,
436 Int_t x, Int_t y, UInt_t w, UInt_t h)
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());
447 }
catch (
const std::exception &) {
453 void CommandBuffer::AddFillPolygon(Drawable_t wid,
const GCValues_t &gc,
454 const Point_t *polygon, Int_t nPoints)
456 assert(polygon != 0 &&
"AddFillPolygon, polygon parameter is null");
457 assert(nPoints > 0 &&
"AddFillPolygon, nPoints <= 0");
460 std::unique_ptr<FillPolygon> cmd(
new FillPolygon(wid, gc, polygon, nPoints));
461 fCommands.push_back(cmd.get());
463 }
catch (
const std::exception &) {
469 void CommandBuffer::AddUpdateWindow(QuartzView *view)
471 assert(view != nil &&
"AddUpdateWindow, view parameter is nil");
474 std::unique_ptr<UpdateWindow> cmd(
new UpdateWindow(view));
475 fCommands.push_back(cmd.get());
477 }
catch (
const std::exception &) {
483 void CommandBuffer::AddDeletePixmap(Pixmap_t pixmapID)
486 std::unique_ptr<DeletePixmap> cmd(
new DeletePixmap(pixmapID));
487 fCommands.push_back(cmd.get());
489 }
catch (
const std::exception &) {
495 void CommandBuffer::AddDrawBoxXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
498 std::unique_ptr<DrawBoxXor> cmd(
new DrawBoxXor(windowID, Point(x1, y1), Point(x2, y2)));
499 fXorOps.push_back(cmd.get());
501 }
catch (
const std::exception &) {
507 void CommandBuffer::AddDrawLineXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
510 std::unique_ptr<DrawLineXor> cmd(
new DrawLineXor(windowID, Point(x1, y1), Point(x2, y2)));
511 fXorOps.push_back(cmd.get());
513 }
catch (
const std::exception &) {
519 void CommandBuffer::Flush(Details::CocoaPrivate *impl)
521 assert(impl != 0 &&
"Flush, impl parameter is null");
527 CGContextRef prevContext = 0;
528 CGContextRef currContext = 0;
529 QuartzView *prevView = nil;
531 for (size_type i = 0, e = fCommands.size(); i < e; ++i) {
532 const Command *cmd = fCommands[i];
536 NSObject<X11Drawable> *drawable = impl->GetDrawable(cmd->fID);
537 if (drawable.fIsPixmap) {
542 QuartzView *view = (QuartzView *)impl->GetWindow(cmd->fID).fContentView;
544 if (prevView != view)
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");
556 view.fContext = currContext;
557 if (prevContext && prevContext != currContext)
558 CGContextFlush(prevContext);
559 prevContext = currContext;
561 const Quartz::CGStateGuard ctxGuard(currContext);
564 if (fClippedRegion.size())
565 CGContextClipToRects(currContext, &fClippedRegion[0], fClippedRegion.size());
568 if (view.fQuartzWindow.fShapeCombineMask)
569 ClipToShapeMask(view, currContext);
573 if (view.fBackBuffer) {
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()];
584 }
catch (
const std::exception &) {
595 CGContextFlush(currContext);
601 void CommandBuffer::FlushXOROps(Details::CocoaPrivate *impl)
603 assert(impl != 0 &&
"FlushXOROps, impl parameter is null");
611 NSObject<X11Drawable> *drawable = impl->GetDrawable(fXorOps[0]->fID);
613 assert([drawable isKindOfClass : [QuartzView
class]] &&
614 "FlushXOROps, drawable must be of type QuartzView");
616 QuartzView *view = (QuartzView *)drawable;
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");
624 const Quartz::CGStateGuard ctxGuard(currContext);
626 CGContextSetAllowsAntialiasing(currContext,
false);
628 view.fContext = currContext;
630 if (view.fBackBuffer) {
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()];
638 for (size_type i = 0, e = fXorOps.size(); i < e; ++i) {
640 fXorOps[i]->Execute(currContext);
647 CGContextFlush(currContext);
649 CGContextSetAllowsAntialiasing(currContext,
true);
652 ClearXOROperations();
656 void CommandBuffer::RemoveOperationsForDrawable(Drawable_t drawable)
658 for (size_type i = 0; i < fCommands.size(); ++i) {
659 if (fCommands[i] && fCommands[i]->HasOperand(drawable)) {
665 for (size_type i = 0; i < fXorOps.size(); ++i) {
666 if (fXorOps[i] && fXorOps[i]->HasOperand(drawable)) {
674 void CommandBuffer::RemoveGraphicsOperationsForWindow(Window_t wid)
676 for (size_type i = 0; i < fCommands.size(); ++i) {
677 if (fCommands[i] && fCommands[i]->HasOperand(wid) &&
678 fCommands[i]->IsGraphicsCommand())
687 void CommandBuffer::RemoveXORGraphicsOperationsForWindow(Window_t wid)
689 for (size_type i = 0; i < fCommands.size(); ++i) {
690 if (fXorOps[i] && fXorOps[i]->HasOperand(wid)) {
698 void CommandBuffer::ClearCommands()
700 for (size_type i = 0, e = fCommands.size(); i < e; ++i)
707 void CommandBuffer::ClearXOROperations()
709 for (size_type i = 0, e = fXorOps.size(); i < e; ++i)
720 bool RectsOverlap(
const NSRect &r1,
const NSRect &r2)
722 if (r2.origin.x >= r1.origin.x + r1.size.width)
724 if (r2.origin.x + r2.size.width <= r1.origin.x)
726 if (r2.origin.y >= r1.origin.y + r1.size.height)
728 if (r2.origin.y + r2.size.height <= r1.origin.y)
737 void CommandBuffer::ClipOverlaps(QuartzView *view)
752 assert(view != nil &&
"ClipOverlaps, view parameter is nil");
754 typedef std::vector<QuartzView *>::reverse_iterator reverse_iterator;
755 typedef std::vector<CGRect>::iterator rect_iterator;
757 fRectsToClip.clear();
758 fClippedRegion.clear();
765 for (QuartzView *v = view; v; v = v.fParentView)
766 fViewBranch.push_back(v);
769 if (fViewBranch.size())
770 fViewBranch.pop_back();
778 const NSRect frame2 = view.frame;
780 for (reverse_iterator it = fViewBranch.rbegin(), eIt = fViewBranch.rend(); it != eIt; ++it) {
781 QuartzView *ancestorView = *it;
782 bool doCheck =
false;
783 for (QuartzView *sibling in [ancestorView.fParentView subviews]) {
784 if (ancestorView == sibling) {
789 }
else if (!doCheck || sibling.fMapState != kIsViewable) {
793 frame1 = sibling.frame;
795 if (!frame1.size.width || !frame1.size.height)
798 frame1.origin = [sibling.fParentView convertPoint : frame1.origin
799 toView : view.fParentView];
802 if (RectsOverlap(frame2, frame1)) {
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);
815 for (QuartzView *child in [view subviews]) {
816 if (child.fMapState != kIsViewable)
819 frame1 = child.frame;
821 if (!frame1.size.width || !frame1.size.height)
824 if (view.fParentView)
825 frame1.origin = [view convertPoint : frame1.origin toView : view.fParentView];
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);
836 if (fRectsToClip.size()) {
840 WidgetRect rect(frame2.origin.x, frame2.origin.y, frame2.origin.x + frame2.size.width,
841 frame2.origin.y + frame2.size.height);
843 BuildClipRegion(rect);
845 if (view.fParentView) {
848 rect_iterator recIt = fClippedRegion.begin(), eIt = fClippedRegion.end();
849 for (; recIt != eIt; ++recIt) {
850 if (!recIt->size.width && !recIt->size.height) {
852 assert(fClippedRegion.size() == 1 &&
"ClipOverlaps, internal logic error");
855 recIt->origin = NSPointToCGPoint([view.fParentView convertPoint :
856 NSPointFromCGPoint(recIt->origin) toView : view]);
864 typedef std::vector<int>::iterator int_iterator;
867 int_iterator BinarySearchLeft(int_iterator first, int_iterator last,
int value)
872 const int_iterator it = std::lower_bound(first, last, value);
873 assert(it != last && (it == first || *it == value) &&
"internal logic error");
876 return it == first && *it != value ? last : it;
880 int_iterator BinarySearchRight(int_iterator first, int_iterator last,
int value)
885 const int_iterator it = std::lower_bound(first, last, value);
886 assert((it == last || *it == value) &&
"internal logic error");
894 void CommandBuffer::BuildClipRegion(
const WidgetRect &rect)
915 typedef std::vector<WidgetRect>::const_iterator rect_const_iterator;
917 assert(fRectsToClip.size() != 0 &&
"BuildClipRegion, nothing to clip");
919 fClippedRegion.clear();
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) {
929 fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));
933 if (recIt->fX1 > rect.fX1)
934 fXBounds.push_back(recIt->fX1);
936 if (recIt->fX2 < rect.fX2)
937 fXBounds.push_back(recIt->fX2);
939 if (recIt->fY1 > rect.fY1)
940 fYBounds.push_back(recIt->fY1);
942 if (recIt->fY2 < rect.fY2)
943 fYBounds.push_back(recIt->fY2);
946 std::sort(fXBounds.begin(), fXBounds.end());
947 std::sort(fYBounds.begin(), fYBounds.end());
950 const int_iterator xBoundsEnd = std::unique(fXBounds.begin(), fXBounds.end());
951 const int_iterator yBoundsEnd = std::unique(fYBounds.begin(), fYBounds.end());
954 const size_type nXBands = size_type(xBoundsEnd - fXBounds.begin()) + 1;
955 const size_type nYBands = size_type(yBoundsEnd - fYBounds.begin()) + 1;
957 fGrid.assign(nXBands * nYBands,
false);
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;
965 const int_iterator right = BinarySearchRight(fXBounds.begin(), xBoundsEnd, recIt->fX2);
966 const size_type lastXBand = right - fXBounds.begin() + 1;
968 const int_iterator bottom = BinarySearchLeft(fYBounds.begin(), yBoundsEnd, recIt->fY1);
969 const size_type firstYBand = bottom == yBoundsEnd ? 0 : bottom - fYBounds.begin() + 1;
971 const int_iterator top = BinarySearchRight(fYBounds.begin(), yBoundsEnd, recIt->fY2);
972 const size_type lastYBand = top - fYBounds.begin() + 1;
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;
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;
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;
995 fClippedRegion.push_back(newRect);
1000 if (!fClippedRegion.size())
1001 fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));