Merge m-c to m-i

This commit is contained in:
Phil Ringnalda 2013-10-03 08:19:39 -07:00
commit 1c2ac46725
44 changed files with 411 additions and 124 deletions

View File

@ -895,6 +895,12 @@
#endif
</toolbar>
<hbox id="downloads-animation-container" mousethrough="always">
<vbox id="downloads-notification-anchor">
<vbox id="downloads-indicator-notification"/>
</vbox>
</hbox>
<toolbarpalette id="BrowserToolbarPalette">
# Update primaryToolbarButtons in browser/themes/shared/browser.inc when adding
@ -912,16 +918,8 @@
ondrop="DownloadsIndicatorView.onDrop(event);"
ondragover="DownloadsIndicatorView.onDragOver(event);"
ondragenter="DownloadsIndicatorView.onDragOver(event);"
xmlns:xbl="http://www.mozilla.org/xbl"
label="&downloads.label;"
tooltiptext="&downloads.tooltip;">
<!-- We need a different binding for the notification and progress bar, which means
we don't get these for free. Adding them in our binding loses them when dragging
to the customize window, so we add them in here as 'real' children -->
<image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
<label class="toolbarbutton-text" crop="right" flex="1"
xbl:inherits="value=label,accesskey,crop"/>
</toolbarbutton>
tooltiptext="&downloads.tooltip;"/>
<toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
observes="viewHistorySidebar" label="&historyButton.label;"

View File

@ -111,6 +111,9 @@
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
<content>
<children />
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
<xul:label class="toolbarbutton-text" crop="right" flex="1"
xbl:inherits="value=label,accesskey,crop"/>
</content>
</binding>
</bindings>

View File

@ -326,18 +326,39 @@ const DownloadsIndicatorView = {
return;
}
function DIV_SEN_callback() {
if (this._notificationTimeout) {
clearTimeout(this._notificationTimeout);
}
let indicator = this.indicator;
indicator.setAttribute("notification", aType);
this._notificationTimeout = setTimeout(
function () indicator.removeAttribute("notification"), 1000);
// If the anchor is not there or its container is hidden, don't show
// a notification
let anchor = DownloadsButton._placeholder;
if (!anchor || !isElementVisible(anchor.parentNode)) {
return;
}
this._ensureOperational(DIV_SEN_callback.bind(this));
if (this._notificationTimeout) {
clearTimeout(this._notificationTimeout);
}
// The notification element is positioned to show in the same location as
// the downloads button. It's not in the downloads button itself in order to
// be able to anchor the notification elsewhere if required, and to ensure
// the notification isn't clipped by overflow properties of the anchor's
// container.
let notifier = this.notifier;
if (notifier.style.transform == '') {
let anchorRect = anchor.getBoundingClientRect();
let notifierRect = notifier.getBoundingClientRect();
let topDiff = anchorRect.top - notifierRect.top;
let leftDiff = anchorRect.left - notifierRect.left;
let heightDiff = anchorRect.height - notifierRect.height;
let widthDiff = anchorRect.width - notifierRect.width;
let translateX = (leftDiff + .5 * widthDiff) + "px";
let translateY = (topDiff + .5 * heightDiff) + "px";
notifier.style.transform = "translate(" + translateX + ", " + translateY + ")";
}
notifier.setAttribute("notification", aType);
this._notificationTimeout = setTimeout(function () {
notifier.removeAttribute("notification");
notifier.style.transform = '';
}, 1000);
},
//////////////////////////////////////////////////////////////////////////////
@ -547,6 +568,12 @@ const DownloadsIndicatorView = {
(this.__indicatorProgress = document.getElementById("downloads-indicator-progress"));
},
get notifier()
{
return this._notifier ||
(this._notifier = document.getElementById("downloads-notification-anchor"));
},
_onCustomizedAway: function() {
this._indicator = null;
this._indicatorAnchor = null;

View File

@ -30,7 +30,6 @@
min="0" max="100"/>
</vbox>
<vbox id="downloads-indicator-icon"/>
<vbox id="downloads-indicator-notification"/>
</stack>
</toolbarbutton>
</overlay>

View File

@ -524,9 +524,6 @@
this._xslideHandler = new CrossSlide.Handler(this, {
REARRANGESTART: this.crossSlideBoundary
});
this.addEventListener("touchstart", this._xslideHandler, false);
this.addEventListener("touchmove", this._xslideHandler, false);
this.addEventListener("touchend", this._xslideHandler, false);
}
// XXX This event was never actually implemented (bug 223411).

View File

@ -28,9 +28,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
"resource://pdf.js/PdfJs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
"resource://gre/modules/DownloadUtils.jsm");

View File

@ -148,7 +148,6 @@ var BrowserUI = {
DialogUI.init();
FormHelperUI.init();
FindHelperUI.init();
PdfJs.init();
} catch(ex) {
Util.dumpLn("Exception in delay load module:", ex.message);
}

View File

@ -432,9 +432,10 @@ MenuPopup.prototype = {
let deferred = Promise.defer();
window.addEventListener("keypress", this, true);
window.addEventListener("click", this, true);
window.addEventListener("mousedown", this, true);
window.addEventListener("touchstart", this, true);
window.addEventListener("scroll", this, true);
Elements.stack.addEventListener("PopupChanged", this, false);
Elements.browsers.addEventListener("PanBegin", this, false);
this._panel.hidden = false;
let popupFrom = !aPositionOptions.bottomAligned ? "above" : "below";
@ -461,9 +462,10 @@ MenuPopup.prototype = {
let deferred = Promise.defer();
window.removeEventListener("keypress", this, true);
window.removeEventListener("click", this, true);
window.removeEventListener("mousedown", this, true);
window.removeEventListener("touchstart", this, true);
window.removeEventListener("scroll", this, true);
Elements.stack.removeEventListener("PopupChanged", this, false);
Elements.browsers.removeEventListener("PanBegin", this, false);
let self = this;
this._panel.addEventListener("transitionend", function popuphidden() {
@ -499,7 +501,9 @@ MenuPopup.prototype = {
this.hide();
}
break;
case "click":
case "mousedown":
case "touchstart":
case "scroll":
if (!this._popup.contains(aEvent.target)) {
aEvent.stopPropagation();
this.hide();
@ -517,9 +521,6 @@ MenuPopup.prototype = {
this.hide();
}
break;
case "PanBegin":
this.hide();
break;
}
}
};

View File

@ -98,9 +98,11 @@ gTests.push({
"context-copy-link"]);
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
win.scrollBy(0, 1);
let hidden = yield promise;
ok(hidden && !(hidden instanceof Error), "scrolling hides the context menu");
win.getSelection().removeAllRanges();
win.scrollBy(0, -1);
////////////////////////////////////////////////////////////
// Context menu in content on a link

View File

@ -23,8 +23,8 @@
<br />
<br />
<br />
<div style="margin: 0; padding: 5px;">
<div style="margin: 0; padding: 5px; margin-bottom: 9999px;">
<span id="text4">hello, I'm sorry but I must be going.</span>
</div>
</body>
</html>
</html>

View File

@ -91,6 +91,7 @@ gTests.push({
tearDown: setUpAndTearDown,
run: function test() {
gInput.selectionStart = gInput.selectionEnd = gInput.value.length;
yield waitForEvent(window, "scroll");
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(190, 17);
@ -137,6 +138,7 @@ gTests.push({
tearDown: setUpAndTearDown,
run: function test() {
gInput.selectionStart = gInput.selectionEnd = 0;
yield waitForEvent(window, "scroll");
let promise = waitForEvent(document, "popupshown");
sendContextMenuClick(230, 17);

File diff suppressed because one or more lines are too long

View File

@ -101,6 +101,11 @@ function CrossSlideHandler(aNode, aThresholds) {
for(let key in aThresholds)
this.thresholds[key] = aThresholds[key];
}
aNode.addEventListener("touchstart", this, false);
aNode.addEventListener("touchmove", this, false);
aNode.addEventListener("touchend", this, false);
aNode.addEventListener("touchcancel", this, false);
aNode.ownerDocument.defaultView.addEventListener("scroll", this, false);
}
CrossSlideHandler.prototype = {
@ -135,6 +140,10 @@ CrossSlideHandler.prototype = {
case "touchmove":
this._onTouchMove(aEvent);
break;
case "scroll":
case "touchcancel":
this.cancel(aEvent);
break;
case "touchend":
this._onTouchEnd(aEvent);
break;

View File

@ -42,6 +42,10 @@ pref("gfx.azpc.fling_repaint_interval", "50"); // prefer 20 fps
pref("gfx.axis.fling_friction", "0.002");
pref("gfx.axis.fling_stopped_threshold", "0.2");
// 0 = free, 1 = standard, 2 = sticky
pref("apzc.axis_lock_mode", 2);
pref("apzc.cross_slide.enabled", true);
// Enable Microsoft TSF support by default for imes.
pref("intl.enable_tsf_support", true);
@ -564,10 +568,10 @@ pref("browser.chrome.toolbar_tips", false);
// Completely disable pdf.js as an option to preview pdfs within firefox.
// Note: if this is not disabled it does not necessarily mean pdf.js is the pdf
// handler just that it is an option.
pref("pdfjs.disabled", false);
pref("pdfjs.disabled", true);
// Used by pdf.js to know the first time firefox is run with it installed so it
// can become the default pdf viewer.
pref("pdfjs.firstRun", true);
pref("pdfjs.firstRun", false);
// The values of preferredAction and alwaysAskBeforeHandling before pdf.js
// became the default.
pref("pdfjs.previousHandler.preferredAction", 0);

View File

@ -601,6 +601,14 @@ documenttab[selected] .documenttab-selection {
list-style-image: url("chrome://browser/skin/images/identity-icons-https-ev.png");
}
#toolbar[startpage] > #urlbar:not([autocomplete]) > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icons-identity-firefox.png");
}
#urlbar[autocomplete] > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icon-autocomplete-search.png");
}
/* Main URL textbox */
#urlbar-edit {
margin: 0 !important;
@ -679,6 +687,14 @@ documenttab[selected] .documenttab-selection {
#stop-button {
list-style-image: url(chrome://browser/skin/images/urlbar-stop@1.4x.png);
}
#toolbar[startpage] > #urlbar:not([autocomplete]) > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icons-identity-firefox@1.4x.png");
}
#urlbar[autocomplete] > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icon-autocomplete-search@1.4x.png");
}
}
@media (min-resolution: @min_res_180pc@) {
@ -705,6 +721,14 @@ documenttab[selected] .documenttab-selection {
#stop-button {
list-style-image: url(chrome://browser/skin/images/urlbar-stop@1.8x.png);
}
#toolbar[startpage] > #urlbar:not([autocomplete]) > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icons-identity-firefox@1.8x.png");
}
#urlbar[autocomplete] > #identity-box > #identity-icon {
list-style-image: url("chrome://browser/skin/images/icon-autocomplete-search@1.8x.png");
}
}
/* navbar edit button: one button out of three - when editing: go, when !editing,

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

View File

@ -56,6 +56,12 @@ chrome.jar:
skin/images/identity-icons-https-ev.png (images/identity-icons-https-ev.png)
skin/images/identity-icons-https-mixed.png (images/identity-icons-https-mixed.png)
skin/images/identity-icons-https.png (images/identity-icons-https.png)
skin/images/icon-autocomplete-search.png (images/icon-autocomplete-search.png)
skin/images/icon-autocomplete-search@1.4x.png (images/icon-autocomplete-search@1.4x.png)
skin/images/icon-autocomplete-search@1.8x.png (images/icon-autocomplete-search@1.8x.png)
skin/images/icons-identity-firefox.png (images/icons-identity-firefox.png)
skin/images/icons-identity-firefox@1.4x.png (images/icons-identity-firefox@1.4x.png)
skin/images/icons-identity-firefox@1.8x.png (images/icons-identity-firefox@1.8x.png)
skin/images/infobar-close.png (images/infobar-close.png)
skin/images/infobar-geolocation.png (images/infobar-geolocation.png)
skin/images/infobar-key.png (images/infobar-key.png)

View File

@ -4,11 +4,17 @@
/*** Status and progress indicator ***/
#downloads-indicator-anchor {
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
#downloads-animation-container {
min-height: 1px;
min-width: 1px;
height: 1px;
margin-bottom: -1px;
/* Makes the outermost animation container element positioned, so that its
contents are rendered over the main browser window in the Z order.
This is required by the animated event notification. */
position: relative;
/* The selected tab may overlap #downloads-indicator-notification */
z-index: 5;
}
toolbar[iconsize="small"] > #downloads-button > #downloads-indicator-anchor {
@ -61,6 +67,8 @@ toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-
background-size: 16px;
background-position: center;
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
@keyframes downloadsIndicatorNotificationStartRight {
@ -75,13 +83,13 @@ toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-
to { opacity: 0; transform: translate(0) scale(1); }
}
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-start.png");
animation-name: downloadsIndicatorNotificationStartRight;
animation-duration: 1s;
}
#downloads-button[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-notification {
animation-name: downloadsIndicatorNotificationStartLeft;
}
@ -91,7 +99,7 @@ toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-
to { opacity: 0; transform: scale(8); }
}
#downloads-button[notification="finish"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="finish"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-finish.png");
animation-name: downloadsIndicatorNotificationFinish;
animation-duration: 1s;

View File

@ -7,12 +7,19 @@
#downloads-indicator-anchor {
min-width: 20px;
min-height: 20px;
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
}
#downloads-animation-container {
min-height: 1px;
min-width: 1px;
height: 1px;
margin-bottom: -1px;
/* Makes the outermost animation container element positioned, so that its
contents are rendered over the main browser window in the Z order.
This is required by the animated event notification. */
position: relative;
/* The selected tab may overlap #downloads-indicator-notification */
z-index: 1;
z-index: 5;
}
/*** Main indicator icon ***/
@ -71,6 +78,8 @@
background-size: 16px;
background-position: center;
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
@keyframes downloadsIndicatorNotificationStartRight {
@ -85,19 +94,19 @@
to { opacity: 0; transform: translate(0) scale(1); }
}
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-start.png");
animation-name: downloadsIndicatorNotificationStartRight;
animation-duration: 1s;
}
@media (min-resolution: 2dppx) {
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-start@2x.png");
}
}
#downloads-button[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-notification {
animation-name: downloadsIndicatorNotificationStartLeft;
}
@ -107,14 +116,14 @@
to { opacity: 0; transform: scale(8); }
}
#downloads-button[notification="finish"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="finish"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-finish.png");
animation-name: downloadsIndicatorNotificationFinish;
animation-duration: 1s;
}
@media (min-resolution: 2dppx) {
#downloads-button[notification="finish"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="finish"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-finish@2x.png");
}
}

View File

@ -4,11 +4,17 @@
/*** Status and progress indicator ***/
#downloads-indicator-anchor {
/* Makes the outermost stack element positioned, so that its contents are
rendered over the main browser window in the Z order. This is required by
the animated event notification. */
#downloads-animation-container {
min-height: 1px;
min-width: 1px;
height: 1px;
margin-bottom: -1px;
/* Makes the outermost animation container element positioned, so that its
contents are rendered over the main browser window in the Z order.
This is required by the animated event notification. */
position: relative;
/* The selected tab may overlap #downloads-indicator-notification */
z-index: 5;
}
/*** Main indicator icon ***/
@ -49,6 +55,8 @@
background-size: 16px;
background-position: center;
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
@keyframes downloadsIndicatorNotificationStartRight {
@ -63,13 +71,13 @@
to { opacity: 0; transform: translate(0) scale(1); }
}
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-start.png");
animation-name: downloadsIndicatorNotificationStartRight;
animation-duration: 1s;
}
#downloads-button[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="start"]:-moz-locale-dir(rtl) > #downloads-indicator-notification {
animation-name: downloadsIndicatorNotificationStartLeft;
}
@ -79,7 +87,7 @@
to { opacity: 0; transform: scale(8); }
}
#downloads-button[notification="finish"] > #downloads-indicator-anchor > #downloads-indicator-notification {
#downloads-notification-anchor[notification="finish"] > #downloads-indicator-notification {
background-image: url("chrome://browser/skin/downloads/download-notification-finish.png");
animation-name: downloadsIndicatorNotificationFinish;
animation-duration: 1s;

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 ts=8 et 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/. */
@ -21,6 +21,7 @@
#include "gfxTypes.h" // for gfxFloat
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
#include "mozilla/Constants.h" // for M_PI
#include "mozilla/EventForwards.h" // for nsEventStatus_*
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitorAutoEnter, etc
@ -64,7 +65,27 @@ namespace layers {
*/
static float gTouchStartTolerance = 1.0f/16.0f;
static const float EPSILON = 0.0001;
static const float EPSILON = 0.0001f;
/**
* Angle from axis within which we stay axis-locked
*/
static const double AXIS_LOCK_ANGLE = M_PI / 6.0; // 30 degrees
/**
* The distance in inches the user must pan before axis lock can be broken
*/
static const float AXIS_BREAKOUT_THRESHOLD = 1.0f/32.0f;
/**
* The angle at which axis lock can be broken
*/
static const double AXIS_BREAKOUT_ANGLE = M_PI / 8.0; // 22.5 degrees
/**
* The preferred axis locking style. See AxisLockMode for possible values.
*/
static int32_t gAxisLockMode = 0;
/**
* Maximum amount of time while panning before sending a viewport change. This
@ -153,6 +174,28 @@ static int gAsyncScrollTimeout = 300;
*/
static bool gAsyncZoomDisabled = false;
/**
* Pref that enables integration with the Metro "cross-slide" gesture.
*/
static bool gCrossSlideEnabled = false;
/**
* Is aAngle within the given threshold of the horizontal axis?
* @param aAngle an angle in radians in the range [0, pi]
* @param aThreshold an angle in radians in the range [0, pi/2]
*/
static bool IsCloseToHorizontal(float aAngle, float aThreshold)
{
return (aAngle < aThreshold || aAngle > (M_PI - aThreshold));
}
// As above, but for the vertical axis.
static bool IsCloseToVertical(float aAngle, float aThreshold)
{
return (fabs(aAngle - (M_PI / 2)) < aThreshold);
}
static TimeStamp sFrameTime;
static TimeStamp
@ -191,6 +234,8 @@ AsyncPanZoomController::InitializeGlobalState()
Preferences::AddIntVarCache(&gAsyncScrollThrottleTime, "apzc.asyncscroll.throttle", gAsyncScrollThrottleTime);
Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apzc.asyncscroll.timeout", gAsyncScrollTimeout);
Preferences::AddBoolVarCache(&gAsyncZoomDisabled, "apzc.asynczoom.disabled", gAsyncZoomDisabled);
Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apzc.cross_slide.enabled", gCrossSlideEnabled);
Preferences::AddIntVarCache(&gAxisLockMode, "apzc.axis_lock_mode", gAxisLockMode);
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
@ -272,6 +317,11 @@ AsyncPanZoomController::GetTouchStartTolerance()
return gTouchStartTolerance;
}
/* static */AsyncPanZoomController::AxisLockMode AsyncPanZoomController::GetAxisLockMode()
{
return static_cast<AxisLockMode>(gAxisLockMode);
}
static CSSPoint
WidgetSpaceToCompensatedViewportSpace(const ScreenPoint& aPoint,
const CSSToScreenScale& aCurrentZoom)
@ -295,7 +345,7 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
// responding in a timely fashion, this only introduces a nearly constant few
// hundred ms of lag.
if (mFrameMetrics.mMayHaveTouchListeners && aEvent.mInputType == MULTITOUCH_INPUT &&
(mState == NOTHING || mState == TOUCHING || mState == PANNING)) {
(mState == NOTHING || mState == TOUCHING || IsPanningState(mState))) {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
SetState(WAITING_LISTENERS);
@ -389,9 +439,7 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent)
}
nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent) {
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
ScreenIntPoint point = touch.mScreenPoint;
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
switch (mState) {
case ANIMATING_ZOOM:
@ -415,6 +463,10 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
break;
case TOUCHING:
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
case CROSS_SLIDING_X:
case CROSS_SLIDING_Y:
case PINCHING:
case WAITING_LISTENERS:
NS_WARNING("Received impossible touch in OnTouchStart");
@ -440,6 +492,12 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
// second tap. Ignore the move if this happens.
return nsEventStatus_eIgnore;
case CROSS_SLIDING_X:
case CROSS_SLIDING_Y:
// While cross-sliding, we don't want to consume any touchmove events for
// panning or zooming, and let the caller handle them instead.
return nsEventStatus_eIgnore;
case TOUCHING: {
float panThreshold = gTouchStartTolerance * APZCTreeManager::GetDPI();
UpdateWithTouchAtDevicePoint(aEvent);
@ -448,12 +506,12 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
}
StartPanning(aEvent);
return nsEventStatus_eConsumeNoDefault;
return StartPanning(aEvent);
}
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
TrackTouch(aEvent);
return nsEventStatus_eConsumeNoDefault;
@ -493,10 +551,14 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore;
case TOUCHING:
case CROSS_SLIDING_X:
case CROSS_SLIDING_Y:
SetState(NOTHING);
return nsEventStatus_eIgnore;
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
{
ReentrantMonitorAutoEnter lock(mMonitor);
ScheduleComposite();
@ -705,19 +767,56 @@ const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
return gfx::Point(mX.GetAccelerationFactor(), mY.GetAccelerationFactor());
}
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
float dx = mX.PanDistance(),
dy = mY.PanDistance();
nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
ReentrantMonitorAutoEnter lock(mMonitor);
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
float dx = mX.PanDistance(point.x);
float dy = mY.PanDistance(point.y);
// When the touch move breaks through the pan threshold, reposition the touch down origin
// so the page won't jump when we start panning.
mX.StartTouch(point.x);
mY.StartTouch(point.y);
mLastEventTime = aEvent.mTime;
if (GetAxisLockMode() == FREE) {
SetState(PANNING);
return nsEventStatus_eConsumeNoDefault;
}
double angle = atan2(dy, dx); // range [-pi, pi]
angle = fabs(angle); // range [0, pi]
SetState(PANNING);
if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
SetState(PANNING);
} else if (IsCloseToHorizontal(angle, AXIS_LOCK_ANGLE)) {
mY.SetScrollingDisabled(true);
if (mX.Scrollable()) {
SetState(PANNING_LOCKED_X);
} else {
SetState(CROSS_SLIDING_X);
mX.SetScrollingDisabled(true);
}
} else if (IsCloseToVertical(angle, AXIS_LOCK_ANGLE)) {
mX.SetScrollingDisabled(true);
if (mY.Scrollable()) {
SetState(PANNING_LOCKED_Y);
} else {
SetState(CROSS_SLIDING_Y);
mY.SetScrollingDisabled(true);
}
} else {
SetState(PANNING);
}
// Don't consume an event that starts a cross-slide.
return IsPanningState(mState) ? nsEventStatus_eConsumeNoDefault
: nsEventStatus_eIgnore;
}
void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent) {
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
ScreenIntPoint point = touch.mScreenPoint;
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
// Probably a duplicate event, just throw it away.
@ -769,9 +868,8 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
}
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
ScreenIntPoint prevTouchPoint(mX.GetPos(), mY.GetPos());
ScreenIntPoint touchPoint = touch.mScreenPoint;
ScreenIntPoint touchPoint = GetFirstTouchScreenPoint(aEvent);
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
// Probably a duplicate event, just throw it away.
@ -779,13 +877,39 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
return;
}
// If we're axis-locked, check if the user is trying to break the lock
if (GetAxisLockMode() == STICKY) {
ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
float dx = mX.PanDistance(point.x);
float dy = mY.PanDistance(point.y);
double angle = atan2(dy, dx); // range [-pi, pi]
angle = fabs(angle); // range [0, pi]
float breakThreshold = AXIS_BREAKOUT_THRESHOLD * APZCTreeManager::GetDPI();
if (fabs(dx) > breakThreshold || fabs(dy) > breakThreshold) {
if (mState == PANNING_LOCKED_X || mState == CROSS_SLIDING_X) {
if (!IsCloseToHorizontal(angle, AXIS_BREAKOUT_ANGLE)) {
mY.SetScrollingDisabled(false);
SetState(PANNING);
}
} else if (mState == PANNING_LOCKED_Y || mState == CROSS_SLIDING_Y) {
if (!IsCloseToVertical(angle, AXIS_BREAKOUT_ANGLE)) {
mX.SetScrollingDisabled(false);
SetState(PANNING);
}
}
}
}
UpdateWithTouchAtDevicePoint(aEvent);
AttemptScroll(prevTouchPoint, touchPoint);
}
SingleTouchData& AsyncPanZoomController::GetFirstSingleTouch(const MultiTouchInput& aEvent) {
return (SingleTouchData&)aEvent.mTouches[0];
ScreenIntPoint& AsyncPanZoomController::GetFirstTouchScreenPoint(const MultiTouchInput& aEvent) {
return ((SingleTouchData&)aEvent.mTouches[0]).mScreenPoint;
}
bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
@ -1365,14 +1489,18 @@ void AsyncPanZoomController::SetState(PanZoomState aNewState) {
}
if (mGeckoContentController) {
if (oldState == PANNING && aNewState != PANNING) {
if (IsPanningState(oldState) && !IsPanningState(aNewState)) {
mGeckoContentController->HandlePanEnd();
} else if (oldState != PANNING && aNewState == PANNING) {
} else if (!IsPanningState(oldState) && IsPanningState(aNewState)) {
mGeckoContentController->HandlePanBegin();
}
}
}
bool AsyncPanZoomController::IsPanningState(PanZoomState aState) {
return (aState == PANNING || aState == PANNING_LOCKED_X || aState == PANNING_LOCKED_Y);
}
void AsyncPanZoomController::TimeoutTouchListeners() {
mTouchListenerTimeoutTask = nullptr;
ContentReceivedTouch(false);

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 ts=8 et 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/. */
@ -391,17 +391,17 @@ protected:
const gfx::Point GetAccelerationVector();
/**
* Gets a reference to the first SingleTouchData from a MultiTouchInput. This
* Gets a reference to the first touch point from a MultiTouchInput. This
* gets only the first one and assumes the rest are either missing or not
* relevant.
*/
SingleTouchData& GetFirstSingleTouch(const MultiTouchInput& aEvent);
ScreenIntPoint& GetFirstTouchScreenPoint(const MultiTouchInput& aEvent);
/**
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
* state and starts actually panning us.
*/
void StartPanning(const MultiTouchInput& aStartPoint);
nsEventStatus StartPanning(const MultiTouchInput& aStartPoint);
/**
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for
@ -484,7 +484,16 @@ private:
NOTHING, /* no touch-start events received */
FLING, /* all touches removed, but we're still scrolling page */
TOUCHING, /* one touch-start event received */
PANNING, /* panning the frame */
PANNING, /* panning the frame */
PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */
PANNING_LOCKED_Y, /* as above for Y axis */
CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture
on a vertically-scrollable view. This used for the
Windows Metro "cross-slide" gesture. */
CROSS_SLIDING_Y, /* as above for Y axis */
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
ANIMATING_ZOOM, /* animated zoom to a new rect */
WAITING_LISTENERS, /* a state halfway between NOTHING and TOUCHING - the user has
@ -492,6 +501,14 @@ private:
prevented the default actions yet. we still need to abort animations. */
};
enum AxisLockMode {
FREE, /* No locking at all */
STANDARD, /* Default axis locking mode that remains locked until pan ends*/
STICKY, /* Allow lock to be broken, with hysteresis */
};
static AxisLockMode GetAxisLockMode();
/**
* Helper to set the current state. Holds the monitor before actually setting
* it. If the monitor is already held by the current thread, it is safe to
@ -499,6 +516,8 @@ private:
*/
void SetState(PanZoomState aState);
bool IsPanningState(PanZoomState mState);
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
TaskThrottler mPaintThrottler;

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 ts=8 et 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/. */
@ -103,13 +103,14 @@ Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
: mPos(0),
mVelocity(0.0f),
mAcceleration(0),
mScrollingDisabled(false),
mAsyncPanZoomController(aAsyncPanZoomController)
{
InitAxisPrefs();
}
void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeDelta) {
float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
float newVelocity = mScrollingDisabled ? 0 : (mPos - aPos) / aTimeDelta.ToMilliseconds();
bool curVelocityBelowThreshold = fabsf(newVelocity) < gVelocityThreshold;
bool directionChange = (mVelocity > 0) != (newVelocity > 0);
@ -133,9 +134,15 @@ void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, const TimeDuration& aTimeD
void Axis::StartTouch(int32_t aPos) {
mStartPos = aPos;
mPos = aPos;
mScrollingDisabled = false;
}
float Axis::AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut) {
if (mScrollingDisabled) {
aOverscrollAmountOut = 0;
return 0;
}
if (fabsf(mVelocity) < gVelocityThreshold) {
mAcceleration = 0;
}
@ -159,6 +166,10 @@ float Axis::PanDistance() {
return fabsf(mPos - mStartPos);
}
float Axis::PanDistance(float aPos) {
return fabsf(aPos - mStartPos);
}
void Axis::EndTouch() {
mAcceleration++;
@ -182,6 +193,13 @@ void Axis::CancelTouch() {
}
}
bool Axis::Scrollable() {
if (mScrollingDisabled) {
return false;
}
return GetCompositionLength() < GetPageLength();
}
bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
if (fabsf(mVelocity) <= gFlingStoppedThreshold) {
// If the velocity is very low, just set it to 0 and stop the fling,
@ -284,7 +302,7 @@ float Axis::ScaleWillOverscrollAmount(ScreenToScreenScale aScale, float aFocus)
}
float Axis::GetVelocity() {
return mVelocity;
return mScrollingDisabled ? 0 : mVelocity;
}
float Axis::GetAccelerationFactor() {

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* vim: set sw=2 ts=8 et 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/. */
@ -69,10 +69,11 @@ public:
/**
* Takes a requested displacement to the position of this axis, and adjusts
* it to account for acceleration (which might increase the displacement)
* and overscroll (which might decrease the displacement; this is to prevent
* the viewport from overscrolling the page rect). If overscroll ocurred,
* its amount is written to |aOverscrollAmountOut|.
* it to account for acceleration (which might increase the displacement),
* overscroll (which might decrease the displacement; this is to prevent the
* viewport from overscrolling the page rect), and axis locking (which might
* prevent any displacement from happening). If overscroll ocurred, its amount
* is written to |aOverscrollAmountOut|.
* The adjusted displacement is returned.
*/
float AdjustDisplacement(float aDisplacement, float& aOverscrollAmountOut);
@ -84,6 +85,12 @@ public:
*/
float PanDistance();
/**
* Gets the distance between the starting position of the touch supplied in
* startTouch() and the supplied position.
*/
float PanDistance(float aPos);
/**
* Applies friction during a fling, or cancels the fling if the velocity is
* too low. Returns true if the fling should continue to another frame, or
@ -92,6 +99,14 @@ public:
*/
bool FlingApplyFrictionOrCancel(const TimeDuration& aDelta);
/*
* Returns true if the page is zoomed in to some degree along this axis such that scrolling is
* possible and this axis has not been scroll locked while panning. Otherwise, returns false.
*/
bool Scrollable();
void SetScrollingDisabled(bool aDisabled) { mScrollingDisabled = aDisabled; }
/**
* Gets the overscroll state of the axis in its current position.
*/
@ -184,6 +199,7 @@ protected:
// they are flinging multiple times in a row very quickly, probably trying to
// reach one of the extremes of the page.
int32_t mAcceleration;
bool mScrollingDisabled; // Whether movement on this axis is locked.
AsyncPanZoomController* mAsyncPanZoomController;
nsTArray<float> mVelocityQueue;
};

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.ActivityResultHandlerMap;
import org.mozilla.gecko.util.ThreadUtils;

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.prompts.PromptService;
import android.app.Activity;
import android.content.Context;

View File

@ -20,6 +20,7 @@ import org.mozilla.gecko.home.BrowserSearch;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.HardwareUtils;

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.widget.Divider;
import org.mozilla.gecko.prompts.PromptInput;
import org.json.JSONArray;
import org.json.JSONException;

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.widget.ArrowPopup;
import org.mozilla.gecko.prompts.PromptInput;
import org.json.JSONArray;
import org.json.JSONException;

View File

@ -12,6 +12,7 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PluginLayer;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.GeckoMenuInflater;
import org.mozilla.gecko.menu.MenuPanel;

View File

@ -10,6 +10,7 @@ import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.GfxInfoThread;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
import org.mozilla.gecko.mozglue.OptionalGeneratedParameter;

View File

@ -126,9 +126,9 @@ FENNEC_JAVA_FILES = \
PrefsHelper.java \
PrivateDataPreference.java \
PrivateTab.java \
Prompt.java \
PromptInput.java \
PromptService.java \
prompts/Prompt.java \
prompts/PromptInput.java \
prompts/PromptService.java \
Restarter.java \
sqlite/ByteBufferInputStream.java \
sqlite/MatrixBlobCursor.java \

View File

@ -62,17 +62,6 @@ public class BookmarksListView extends HomeListView
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final ListView list = (ListView) parent;
final int headerCount = list.getHeaderViewsCount();
if (position < headerCount) {
// The click is on a header, don't do anything.
return;
}
// Absolute position for the adapter.
position -= headerCount;
final BookmarksListAdapter adapter = getBookmarksListAdapter();
if (adapter.isShowingChildFolder()) {
if (position == 0) {

View File

@ -3,11 +3,14 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.prompts;
import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.DateTimePicker;
import org.mozilla.gecko.R;
import org.mozilla.gecko.GeckoAppShell;
import org.json.JSONArray;
import org.json.JSONObject;

View File

@ -3,8 +3,9 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.prompts;
import org.mozilla.gecko.AllCapsTextView;
import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.DateTimePicker;
@ -40,7 +41,7 @@ import java.util.GregorianCalendar;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
class PromptInput {
public class PromptInput {
private final JSONObject mJSONInput;
protected final String mLabel;

View File

@ -3,8 +3,10 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.prompts;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.util.ThreadUtils;
@ -27,7 +29,7 @@ public class PromptService implements GeckoEventResponder {
mContext = context;
}
void destroy() {
public void destroy() {
GeckoAppShell.getEventDispatcher().unregisterEventListener("Prompt:Show", this);
GeckoAppShell.getEventDispatcher().unregisterEventListener("Prompt:ShowTop", this);
}

View File

@ -64,7 +64,7 @@ public class FaviconView extends ImageView {
private void formatImage() {
// If we're called before bitmap is set, or before size is set, show blank.
if (mIconBitmap == null || mActualWidth == 0 || mActualHeight == 0) {
clearImage();
showNoImage();
return;
}
@ -157,12 +157,16 @@ public class FaviconView extends ImageView {
hideBackground();
}
private void showNoImage() {
setImageBitmap(null);
hideBackground();
}
/**
* Clear image and background shown by this view.
*/
public void clearImage() {
setImageResource(0);
hideBackground();
showNoImage();
mUnscaledBitmap = null;
mIconBitmap = null;
mIconKey = null;

View File

@ -519,7 +519,7 @@ body {
background-image: url('chrome://browser/skin/images/reader-style-icon-mdpi.png');
}
@media screen and (min-resolution: 200dpi) {
@media screen and (min-resolution: 1.25dppx) {
.dropdown-arrow {
background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png');
}
@ -557,7 +557,7 @@ body {
}
}
@media screen and (min-resolution: 300dpi) {
@media screen and (min-resolution: 2dppx) {
.dropdown-arrow {
background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png');
}

View File

@ -276,6 +276,12 @@ pref("media.video_stats.enabled", true);
// Whether to enable the audio writing APIs on the audio element
pref("media.audio_data.enabled", true);
// Whether to lock touch scrolling to one axis at a time
// 0 = FREE (No locking at all)
// 1 = STANDARD (Once locked, remain locked until scrolling ends)
// 2 = STICKY (Allow lock to be broken, with hysteresis)
pref("apzc.axis_lock_mode", 0);
#ifdef XP_MACOSX
// Whether to run in native HiDPI mode on machines with "Retina"/HiDPI display;
// <= 0 : hidpi mode disabled, display will just use pixel-based upscaling