void
GradientStopsView::UpdateView()
{
  DrawTarget *dt = ui->dtWidget->GetDT();

  dt->FillRect(Rect(0, 0, 100000, 100000), ColorPattern(Color(0.5f, 0.5f, 0.5f, 1.0f)));

  RefPtr<GradientStops> stops = mTranslator->LookupGradientStops(mRefPtr);

  ui->listWidget->clear();
  if (!stops) {
    dt->Flush();
    ui->dtWidget->redraw();
    ui->listWidget->addItem("Dead");
    return;
  }

  IntSize dstSize = dt->GetSize();

  RefPtr<DrawTarget> tmpdt = dt->CreateSimilarDrawTarget(IntSize(20, 20), SurfaceFormat::B8G8R8X8);
  tmpdt->FillRect(Rect(0, 0, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f)));
  tmpdt->FillRect(Rect(10, 10, 10, 10), ColorPattern(Color(1.0f, 1.0f, 1.0f)));
  tmpdt->FillRect(Rect(10, 0, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f)));
  tmpdt->FillRect(Rect(0, 10, 10, 10), ColorPattern(Color(0.7f, 0.7f, 0.7f)));
  RefPtr<SourceSurface> src = tmpdt->Snapshot();
  tmpdt = NULL;

  Rect dstRect(0, 0, dstSize.width, dstSize.height);
  dt->FillRect(dstRect, SurfacePattern(src, ExtendMode::REPEAT));

  dt->FillRect(dstRect, LinearGradientPattern(Point(0, dstSize.height / 2), Point(dstSize.width, dstSize.height / 2), stops));

  dt->Flush();
  ui->dtWidget->redraw();
}
double
PlaybackManager::GetEventTiming(uint32_t aID, bool aAllowBatching, bool aIgnoreFirst, 
                                bool aDoFlush, bool aForceCompletion, double *aStdDev)
{
  if (!aID) {
    return 0;
  }

  uint32_t currentEvent = mCurrentEvent;

  HighPrecisionMeasurement timer;
  const int sIterations = 50;
  const int N = 10;

  double results[sIterations];
  
  DrawTarget *destinedDT = nullptr;

  // We need to ensure clips still always get pushed and popped in pairs!
  RecordedEvent *popEvent = nullptr;
  RecordedEvent *pushEvent = nullptr;
  if (IsClipPop(aID)) {
    uint32_t pushID;
    if (!FindCorrespondingClipID(aID, &pushID)) {
      // EEP! This is bad.
      MOZ_ASSERT(false);
    }
    pushEvent = mRecordedEvents[pushID];
  } else if (IsClipPush(aID)) {
    uint32_t popID;
    if (!FindCorrespondingClipID(aID, &popID)) {
      // EEP! This is bad.
      MOZ_ASSERT(false);
    }
    popEvent = mRecordedEvents[popID];
  }

  for (int c = 0; c < N; c++) {
    PlayToEvent(0);
    PlayToEvent(aID);

    if (mRecordedEvents[aID]->GetDestinedDT()) {
      destinedDT = LookupDrawTarget(mRecordedEvents[aID]->GetDestinedDT());
    }

    if (aIgnoreFirst) {
      // Execute the call once to ignore the first execution.
      if (pushEvent) {
        PlaybackEvent(pushEvent);
      }

      PlaybackEvent(mRecordedEvents[aID]);

      if (popEvent) {
        PlaybackEvent(popEvent);
      }
    }

    timer.Start();
    for (int i = 0; i < sIterations; i++) {

      if (pushEvent) {
        PlaybackEvent(pushEvent);
      }

      PlaybackEvent(mRecordedEvents[aID]);

      if (popEvent) {
        PlaybackEvent(popEvent);
      }

      if (!aAllowBatching) {
        if (destinedDT) {
          destinedDT->Flush();
        }
      }
    }
    if (destinedDT && aDoFlush) {
      destinedDT->Flush();
    }
    if (aForceCompletion) {
      ForceCompletion();
    }
    results[c] = timer.Measure();
  }

  double average = 0;
  for (int i = 0; i < N; i++) {
    average += results[i];
  }

  // Bjacob suggested we work with the median here instead of the mean,
  // making us less sensitive to outliers. This is probably a good idea and
  // should be looked in to.

  average /= double(N);
  
  double sqDiffSum = 0;
  for (int i = 0; i < N; i++) {
    sqDiffSum += pow(results[i] - average, 2);
  }

  sqDiffSum /= double(N);

  *aStdDev = sqrt(sqDiffSum) / double(sIterations);

  PlayToEvent(0);
  PlayToEvent(currentEvent + 1);  

  return average / double(sIterations);
}