コード例 #1
0
void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, ParentLayerCoord aAdditionalDelta, uint32_t aTimestampMs) {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) {
    // See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS.
    // We still update mPos so that the positioning is correct (and we don't run
    // into problems like bug 1042734) but the velocity will remain where it was.
    // In particular we don't update either mVelocitySampleTimeMs or
    // mVelocitySamplePos so that eventually when we do get an event with the
    // required time delta we use the corresponding distance delta as well.
    AXIS_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
        mAsyncPanZoomController, Name(), (aTimestampMs - mVelocitySampleTimeMs));
    mPos = aPos;
    return;
  }

  float newVelocity = mAxisLocked ? 0.0f : (float)(mVelocitySamplePos - aPos + aAdditionalDelta) / (float)(aTimestampMs - mVelocitySampleTimeMs);

  newVelocity = ApplyFlingCurveToVelocity(newVelocity);

  AXIS_LOG("%p|%s updating velocity to %f with touch\n",
    mAsyncPanZoomController, Name(), newVelocity);
  mVelocity = newVelocity;
  mPos = aPos;
  mVelocitySampleTimeMs = aTimestampMs;
  mVelocitySamplePos = aPos;

  AddVelocityToQueue(aTimestampMs, mVelocity);
}
コード例 #2
0
ファイル: Axis.cpp プロジェクト: cbradley857/gecko-dev
void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, ParentLayerCoord aAdditionalDelta, uint32_t aTimestampMs) {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  if (aTimestampMs <= mVelocitySampleTimeMs + MIN_VELOCITY_SAMPLE_TIME_MS) {
    // See also the comment on MIN_VELOCITY_SAMPLE_TIME_MS.
    // We still update mPos so that the positioning is correct (and we don't run
    // into problems like bug 1042734) but the velocity will remain where it was.
    // In particular we don't update either mVelocitySampleTimeMs or
    // mVelocitySamplePos so that eventually when we do get an event with the
    // required time delta we use the corresponding distance delta as well.
    AXIS_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
        mAsyncPanZoomController, Name(), (aTimestampMs - mVelocitySampleTimeMs));
    mPos = aPos;
    return;
  }

  float newVelocity = mAxisLocked ? 0.0f : (float)(mVelocitySamplePos - aPos + aAdditionalDelta) / (float)(aTimestampMs - mVelocitySampleTimeMs);
  if (gfxPrefs::APZMaxVelocity() > 0.0f) {
    bool velocityIsNegative = (newVelocity < 0);
    newVelocity = fabs(newVelocity);

    float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity());
    newVelocity = std::min(newVelocity, maxVelocity);

    if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
      float curveThreshold = ToLocalVelocity(gfxPrefs::APZCurveThreshold());
      if (newVelocity > curveThreshold) {
        // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve
        float scale = maxVelocity - curveThreshold;
        float funcInput = (newVelocity - curveThreshold) / scale;
        float funcOutput = gVelocityCurveFunction->GetValue(funcInput);
        float curvedVelocity = (funcOutput * scale) + curveThreshold;
        AXIS_LOG("%p|%s curving up velocity from %f to %f\n",
          mAsyncPanZoomController, Name(), newVelocity, curvedVelocity);
        newVelocity = curvedVelocity;
      }
    }

    if (velocityIsNegative) {
      newVelocity = -newVelocity;
    }
  }

  AXIS_LOG("%p|%s updating velocity to %f with touch\n",
    mAsyncPanZoomController, Name(), newVelocity);
  mVelocity = newVelocity;
  mPos = aPos;
  mVelocitySampleTimeMs = aTimestampMs;
  mVelocitySamplePos = aPos;

  // Limit queue size pased on pref
  mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, mVelocity));
  if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
    mVelocityQueue.RemoveElementAt(0);
  }
}
コード例 #3
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
void Axis::UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, uint32_t aTimestampMs) {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  if (aTimestampMs == mPosTimeMs) {
    // This could be a duplicate event, or it could be a legitimate event
    // on some platforms that generate events really fast. As a compromise
    // update mPos so we don't run into problems like bug 1042734, even though
    // that means the velocity will be stale. Better than doing a divide-by-zero.
    mPos = aPos;
    return;
  }

  float newVelocity = mAxisLocked ? 0.0f : (float)(mPos - aPos) / (float)(aTimestampMs - mPosTimeMs);
  if (gfxPrefs::APZMaxVelocity() > 0.0f) {
    bool velocityIsNegative = (newVelocity < 0);
    newVelocity = fabs(newVelocity);

    float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity());
    newVelocity = std::min(newVelocity, maxVelocity);

    if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
      float curveThreshold = ToLocalVelocity(gfxPrefs::APZCurveThreshold());
      if (newVelocity > curveThreshold) {
        // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve
        float scale = maxVelocity - curveThreshold;
        float funcInput = (newVelocity - curveThreshold) / scale;
        float funcOutput = gVelocityCurveFunction->GetValue(funcInput);
        float curvedVelocity = (funcOutput * scale) + curveThreshold;
        AXIS_LOG("%p|%s curving up velocity from %f to %f\n",
          mAsyncPanZoomController, Name(), newVelocity, curvedVelocity);
        newVelocity = curvedVelocity;
      }
    }

    if (velocityIsNegative) {
      newVelocity = -newVelocity;
    }
  }

  AXIS_LOG("%p|%s updating velocity to %f with touch\n",
    mAsyncPanZoomController, Name(), newVelocity);
  mVelocity = newVelocity;
  mPos = aPos;
  mPosTimeMs = aTimestampMs;

  // Limit queue size pased on pref
  mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, mVelocity));
  if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
    mVelocityQueue.RemoveElementAt(0);
  }
}
コード例 #4
0
float Axis::ApplyFlingCurveToVelocity(float aVelocity) const {
  float newVelocity = aVelocity;
  if (gfxPrefs::APZMaxVelocity() > 0.0f) {
    bool velocityIsNegative = (newVelocity < 0);
    newVelocity = fabs(newVelocity);

    float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity());
    newVelocity = std::min(newVelocity, maxVelocity);

    if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
      float curveThreshold = ToLocalVelocity(gfxPrefs::APZCurveThreshold());
      if (newVelocity > curveThreshold) {
        // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve
        float scale = maxVelocity - curveThreshold;
        float funcInput = (newVelocity - curveThreshold) / scale;
        float funcOutput =
          gVelocityCurveFunction->GetValue(funcInput,
            ComputedTimingFunction::BeforeFlag::Unset);
        float curvedVelocity = (funcOutput * scale) + curveThreshold;
        AXIS_LOG("%p|%s curving up velocity from %f to %f\n",
          mAsyncPanZoomController, Name(), newVelocity, curvedVelocity);
        newVelocity = curvedVelocity;
      }
    }

    if (velocityIsNegative) {
      newVelocity = -newVelocity;
    }
  }

  return newVelocity;
}
コード例 #5
0
void Axis::CancelGesture() {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  AXIS_LOG("%p|%s cancelling touch, clearing velocity queue\n",
    mAsyncPanZoomController, Name());
  mVelocity = 0.0f;
  mVelocityQueue.Clear();
}
コード例 #6
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
void Axis::CancelTouch() {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  AXIS_LOG("%p|%s cancelling touch, clearing velocity queue\n",
    mAsyncPanZoomController, Name());
  mVelocity = 0.0f;
  while (!mVelocityQueue.IsEmpty()) {
    mVelocityQueue.RemoveElementAt(0);
  }
}
コード例 #7
0
ファイル: Axis.cpp プロジェクト: luke-chang/gecko-1
bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta,
                                      float aFriction,
                                      float aThreshold) {
  if (fabsf(mVelocity) <= aThreshold) {
    // If the velocity is very low, just set it to 0 and stop the fling,
    // otherwise we'll just asymptotically approach 0 and the user won't
    // actually see any changes.
    mVelocity = 0.0f;
    return false;
  } else {
    mVelocity *= pow(1.0f - aFriction, float(aDelta.ToMilliseconds()));
  }
  AXIS_LOG("%p|%s reduced velocity to %f due to friction\n",
    mAsyncPanZoomController, Name(), mVelocity);
  return true;
}
コード例 #8
0
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
  mMSDModel.Simulate(aDelta);
  mOverscroll = mMSDModel.GetPosition();

  if (mMSDModel.IsFinished(1.0)) {
    // "Jump" to the at-rest state. The jump shouldn't be noticeable as the
    // velocity and overscroll are already low.
    AXIS_LOG("%p|%s oscillation dropped below threshold, going to rest\n",
      mAsyncPanZoomController, Name());
    ClearOverscroll();
    mVelocity = 0;
    return false;
  }

  // Otherwise, continue the animation.
  return true;
}
コード例 #9
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
bool Axis::AdjustDisplacement(ParentLayerCoord aDisplacement,
                              /* ParentLayerCoord */ float& aDisplacementOut,
                              /* ParentLayerCoord */ float&
                              aOverscrollAmountOut,
                              bool forceOverscroll /* = false */)
{
  if (mAxisLocked) {
    aOverscrollAmountOut = 0;
    aDisplacementOut = 0;
    return false;
  }
  if (forceOverscroll) {
    aOverscrollAmountOut = aDisplacement;
    aDisplacementOut = 0;
    return false;
  }

  StopSamplingOverscrollAnimation();

  ParentLayerCoord displacement = aDisplacement;

  // First consume any overscroll in the opposite direction along this axis.
  ParentLayerCoord consumedOverscroll = 0;
  if (mOverscroll > 0 && aDisplacement < 0) {
    consumedOverscroll = std::min(mOverscroll, -aDisplacement);
  } else if (mOverscroll < 0 && aDisplacement > 0) {
    consumedOverscroll = 0.f - std::min(-mOverscroll, aDisplacement);
  }
  mOverscroll -= consumedOverscroll;
  displacement += consumedOverscroll;

  // Split the requested displacement into an allowed displacement that does
  // not overscroll, and an overscroll amount.
  aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement);
  if (aOverscrollAmountOut != 0.0f) {
    // No need to have a velocity along this axis anymore; it won't take us
    // anywhere, so we're just spinning needlessly.
    AXIS_LOG("%p|%s has overscrolled, clearing velocity\n",
      mAsyncPanZoomController, Name());
    mVelocity = 0.0f;
    displacement -= aOverscrollAmountOut;
  }
  aDisplacementOut = displacement;
  return fabsf(consumedOverscroll) > EPSILON;
}
コード例 #10
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
void Axis::EndTouch(uint32_t aTimestampMs) {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  mVelocity = 0;
  int count = 0;
  while (!mVelocityQueue.IsEmpty()) {
    uint32_t timeDelta = (aTimestampMs - mVelocityQueue[0].first);
    if (timeDelta < gfxPrefs::APZVelocityRelevanceTime()) {
      count++;
      mVelocity += mVelocityQueue[0].second;
    }
    mVelocityQueue.RemoveElementAt(0);
  }
  if (count > 1) {
    mVelocity /= count;
  }
  AXIS_LOG("%p|%s ending touch, computed velocity %f\n",
    mAsyncPanZoomController, Name(), mVelocity);
}
コード例 #11
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
  // Short-circuit early rather than running through all the sampling code.
  if (mVelocity == 0.0f && mOverscroll == 0.0f) {
    return false;
  }

  // We approximate the curve traced out by the velocity of the spring
  // over time by breaking up the curve into small segments over which we
  // consider the velocity to be constant. If the animation is sampled
  // sufficiently often, then treating |aDelta| as a single segment of this
  // sort would be fine, but the frequency at which the animation is sampled
  // can be affected by external factors, and as the segment size grows larger,
  // the approximation gets worse and the approximated curve can even diverge
  // (i.e. oscillate forever, with displacements of increasing absolute value)!
  // To avoid this, we break up |aDelta| into smaller segments of length 1 ms
  // each, and a segment of any remaining fractional milliseconds.
  double milliseconds = aDelta.ToMilliseconds();
  int wholeMilliseconds = (int) aDelta.ToMilliseconds();
  double fractionalMilliseconds = milliseconds - wholeMilliseconds;
  for (int i = 0; i < wholeMilliseconds; ++i) {
    StepOverscrollAnimation(1);
  }
  StepOverscrollAnimation(fractionalMilliseconds);

  // If both the velocity and the displacement fall below a threshold, stop
  // the animation so we don't continue doing tiny oscillations that aren't
  // noticeable.
  if (fabs(mOverscroll) < gfxPrefs::APZOverscrollStopDistanceThreshold() &&
      fabs(mVelocity) < gfxPrefs::APZOverscrollStopVelocityThreshold()) {
    // "Jump" to the at-rest state. The jump shouldn't be noticeable as the
    // velocity and overscroll are already low.
    AXIS_LOG("%p|%s oscillation dropped below threshold, going to rest\n",
      mAsyncPanZoomController, Name());
    ClearOverscroll();
    mVelocity = 0;
    return false;
  }

  // Otherwise, continue the animation.
  return true;
}
コード例 #12
0
void Axis::EndTouch(uint32_t aTimestampMs) {
  // mVelocityQueue is controller-thread only
  APZThreadUtils::AssertOnControllerThread();

  mAxisLocked = false;
  mVelocity = 0;
  int count = 0;
  for (const auto& e : mVelocityQueue) {
    uint32_t timeDelta = (aTimestampMs - e.first);
    if (timeDelta < gfxPrefs::APZVelocityRelevanceTime()) {
      count++;
      mVelocity += e.second;
    }
  }
  mVelocityQueue.Clear();
  if (count > 1) {
    mVelocity /= count;
  }
  AXIS_LOG("%p|%s ending touch, computed velocity %f\n",
    mAsyncPanZoomController, Name(), mVelocity);
}
コード例 #13
0
void Axis::SetVelocity(float aVelocity) {
  AXIS_LOG("%p|%s direct-setting velocity to %f\n",
    mAsyncPanZoomController, Name(), aVelocity);
  mVelocity = aVelocity;
}
コード例 #14
0
ファイル: Axis.cpp プロジェクト: RobertJGabriel/Waterfox
void Axis::StepOverscrollAnimation(double aStepDurationMilliseconds) {
  // Apply spring physics to the overscroll as time goes on.
  // Note: this method of sampling isn't perfectly smooth, as it assumes
  // a constant velocity over 'aDelta', instead of an accelerating velocity.
  // (The way we applying friction to flings has the same issue.)
  // Hooke's law with damping:
  //   F = -kx - bv
  // where
  //   k is a constant related to the stiffness of the spring
  //     The larger the constant, the stiffer the spring.
  //   x is the displacement of the end of the spring from its equilibrium
  //     In our scenario, it's the amount of overscroll on the axis.
  //   b is a constant that provides damping (friction)
  //   v is the velocity of the point at the end of the spring
  // See http://gafferongames.com/game-physics/spring-physics/
  const float kSpringStiffness = gfxPrefs::APZOverscrollSpringStiffness();
  const float kSpringFriction = gfxPrefs::APZOverscrollSpringFriction();

  // Apply spring force.
  float springForce = -1 * kSpringStiffness * mOverscroll;
  // Assume unit mass, so force = acceleration.
  float oldVelocity = mVelocity;
  mVelocity += springForce * aStepDurationMilliseconds;

  // Apply dampening.
  mVelocity *= pow(double(1 - kSpringFriction), aStepDurationMilliseconds);
  AXIS_LOG("%p|%s sampled overscroll animation, leaving velocity at %f\n",
    mAsyncPanZoomController, Name(), mVelocity);

  // At the peak of each oscillation, record new offset and scaling factors for
  // overscroll, to ensure that GetOverscroll always returns a value of the
  // same sign, and that this value is correctly adjusted as the spring is
  // dampened.
  bool velocitySignChange = (oldVelocity * mVelocity) < 0;
  if (mFirstOverscrollAnimationSample == 0.0f) {
    mFirstOverscrollAnimationSample = mOverscroll;

    // It's possible to start sampling overscroll with velocity == 0, or
    // velocity in the opposite direction of overscroll, so make sure we
    // correctly record the peak in this case.
    if (mOverscroll != 0 && ((mOverscroll > 0 ? oldVelocity : -oldVelocity) <= 0.0f)) {
      velocitySignChange = true;
    }
  }
  if (velocitySignChange) {
    bool oddOscillation = (mOverscroll.value * mFirstOverscrollAnimationSample.value) < 0.0f;
    mLastOverscrollPeak = oddOscillation ? mOverscroll : -mOverscroll;
    mOverscrollScale = 2.0f;
  }

  // Adjust the amount of overscroll based on the velocity.
  // Note that we allow for oscillations.
  mOverscroll += (mVelocity * aStepDurationMilliseconds);

  // Our mechanism for translating a set of mOverscroll values that oscillate
  // around zero to a set of GetOverscroll() values that have the same sign
  // (so content is always stretched, never compressed) assumes that
  // mOverscroll does not exceed mLastOverscrollPeak in magnitude. If our
  // calculations were exact, this would be the case, as a dampened spring
  // should never attain a displacement greater in magnitude than a previous
  // peak. In our approximation calculations, however, this may not hold
  // exactly. To ensure the assumption is not violated, we clamp the magnitude
  // of mOverscroll.
  if (mLastOverscrollPeak != 0 && fabs(mOverscroll) > fabs(mLastOverscrollPeak)) {
    mOverscroll = (mOverscroll >= 0) ? fabs(mLastOverscrollPeak) : -fabs(mLastOverscrollPeak);
  }
}