commit 95b008b232fb75f09541ac43e3d1ef5482ad2590 Author: Markus Stange mstange@themasta.com Date: Sat Jul 16 17:07:45 2016 -0400
Bug 1070710 - Add mozilla::ViewRegion which assembles a LayoutDeviceIntRegion as NSViews. r=spohl
MozReview-Commit-ID: RrVzLcv27T
--HG-- extra : amend_source : d14dc262bf300a81feaf03954d5783ea1c7451cb extra : histedit_source : aa39b53c122a719a5181b5a41d5351bbdf04cbd8 --- widget/cocoa/ViewRegion.h | 53 ++++++++++++++++++++++++++++++++ widget/cocoa/ViewRegion.mm | 70 +++++++++++++++++++++++++++++++++++++++++++ widget/cocoa/moz.build | 1 + widget/cocoa/nsScreenCocoa.mm | 4 +-- 4 files changed, 126 insertions(+), 2 deletions(-)
diff --git a/widget/cocoa/ViewRegion.h b/widget/cocoa/ViewRegion.h new file mode 100644 index 0000000..a8efcca --- /dev/null +++ b/widget/cocoa/ViewRegion.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ViewRegion_h +#define ViewRegion_h + +#include "Units.h" +#include "nsTArray.h" + +@class NSView; + +namespace mozilla { + +/** + * Manages a set of NSViews to cover a LayoutDeviceIntRegion. + */ +class ViewRegion { +public: + ~ViewRegion(); + + mozilla::LayoutDeviceIntRegion Region() { return mRegion; } + + /** + * Update the region. + * @param aRegion The new region. + * @param aCoordinateConverter The nsChildView to use for converting + * LayoutDeviceIntRect device pixel coordinates into Cocoa NSRect coordinates. + * @param aContainerView The view that's going to be the superview of the + * NSViews which will be created for this region. + * @param aViewCreationCallback A block that instantiates new NSViews. + * @return Whether or not the region changed. + */ + bool UpdateRegion(const mozilla::LayoutDeviceIntRegion& aRegion, + const nsChildView& aCoordinateConverter, + NSView* aContainerView, + NSView* (^aViewCreationCallback)()); + + /** + * Return an NSView from the region, if there is any. + */ + NSView* GetAnyView() { return mViews.Length() > 0 ? mViews[0] : nil; } + +private: + mozilla::LayoutDeviceIntRegion mRegion; + nsTArray<NSView*> mViews; +}; + +} // namespace mozilla + +#endif // ViewRegion_h diff --git a/widget/cocoa/ViewRegion.mm b/widget/cocoa/ViewRegion.mm new file mode 100644 index 0000000..3459849 --- /dev/null +++ b/widget/cocoa/ViewRegion.mm @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ViewRegion.h" +#import <Cocoa/Cocoa.h> + +using namespace mozilla; + +ViewRegion::~ViewRegion() +{ + for (size_t i = 0; i < mViews.Length(); i++) { + [mViews[i] removeFromSuperview]; + } +} + +bool +ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion, + const nsChildView& aCoordinateConverter, + NSView* aContainerView, + NSView* (^aViewCreationCallback)()) +{ + if (mRegion == aRegion) { + return false; + } + + // We need to construct the required region using as many EffectViews + // as necessary. We try to update the geometry of existing views if + // possible, or create new ones or remove old ones if the number of + // rects in the region has changed. + + nsTArray<NSView*> viewsToRecycle; + mViews.SwapElements(viewsToRecycle); + // The mViews array is now empty. + + LayoutDeviceIntRegion::RectIterator iter(aRegion); + const LayoutDeviceIntRect* iterRect = nullptr; + for (size_t i = 0; (iterRect = iter.Next()) || i < viewsToRecycle.Length(); ++i) { + if (iterRect) { + NSView* view = nil; + NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(*iterRect); + if (i < viewsToRecycle.Length()) { + view = viewsToRecycle[i]; + } else { + view = aViewCreationCallback(); + [aContainerView addSubview:view]; + + // Now that the view is in the view hierarchy, it'll be kept alive by + // its superview, so we can drop our reference. + [view release]; + } + if (!NSEqualRects(rect, [view frame])) { + [view setFrame:rect]; + } + [view setNeedsDisplay:YES]; + mViews.AppendElement(view); + iter.Next(); + } else { + // Our new region is made of fewer rects than the old region, so we can + // remove this view. We only have a weak reference to it, so removing it + // from the view hierarchy will release it. + [viewsToRecycle[i] removeFromSuperview]; + } + } + + mRegion = aRegion; + return true; +} diff --git a/widget/cocoa/moz.build b/widget/cocoa/moz.build index aa8bfac..21b9369 100644 --- a/widget/cocoa/moz.build +++ b/widget/cocoa/moz.build @@ -58,6 +58,7 @@ UNIFIED_SOURCES += [ 'SwipeTracker.mm', 'TextInputHandler.mm', 'VibrancyManager.mm', + 'ViewRegion.mm', 'WidgetTraceEvent.mm', ]
diff --git a/widget/cocoa/nsScreenCocoa.mm b/widget/cocoa/nsScreenCocoa.mm index 1b72bbf..bd3eef3 100644 --- a/widget/cocoa/nsScreenCocoa.mm +++ b/widget/cocoa/nsScreenCocoa.mm @@ -44,7 +44,7 @@ nsScreenCocoa::GetRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t { NSRect frame = [mScreen frame];
- LayoutDeviceIntRect r = + mozilla::LayoutDeviceIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor());
*outX = r.x; @@ -60,7 +60,7 @@ nsScreenCocoa::GetAvailRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int { NSRect frame = [mScreen visibleFrame];
- LayoutDeviceIntRect r = + mozilla::LayoutDeviceIntRect r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, BackingScaleFactor());
*outX = r.x;