普通文本  |  317行  |  9.31 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "pdf/fading_controls.h"

#include "base/logging.h"
#include "base/stl_util.h"
#include "pdf/draw_utils.h"
#include "pdf/resource_consts.h"
#include "ppapi/cpp/input_event.h"

namespace chrome_pdf {

const uint32 kFadingAlphaShift = 64;
const uint32 kSplashFadingAlphaShift = 16;

FadingControls::FadingControls()
    : state_(NONE), current_transparency_(kOpaqueAlpha), fading_timer_id_(0),
      current_capture_control_(kInvalidControlId),
      fading_timeout_(kFadingTimeoutMs), alpha_shift_(kFadingAlphaShift),
      splash_(false), splash_timeout_(0) {
}

FadingControls::~FadingControls() {
  STLDeleteElements(&controls_);
}

bool FadingControls::CreateFadingControls(
    uint32 id, const pp::Rect& rc, bool visible,
    Control::Owner* owner, uint8 transparency) {
  current_transparency_ = transparency;
  return Control::Create(id, rc, visible, owner);
}

void FadingControls::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
  // When this control is set to invisible the individual controls are not.
  // So we need to check for visible() here.
  if (!visible())
    return;

  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    (*iter)->Paint(image_data, rc);
  }
}

bool FadingControls::HandleEvent(const pp::InputEvent& event) {
  if (!visible())
    return false;

  pp::MouseInputEvent mouse_event(event);
  if (mouse_event.is_null())
    return NotifyControls(event);

  pp::Point pt = mouse_event.GetPosition();

  bool is_mouse_click =
      mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN ||
      mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP;

  if (rect().Contains(pt)) {
    CancelSplashMode();
    FadeIn();

    // Eat mouse click if are invisible or just fading in.
    // That prevents accidental clicks on the controls for touch devices.
    bool eat_mouse_click =
        (state_ == FADING_IN || current_transparency_ == kTransparentAlpha);
    if (eat_mouse_click && is_mouse_click &&
        mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
      return true;  // Eat this event here.
  }

  if ((!rect().Contains(pt)) ||
      event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
    if (!splash_)
      FadeOut();
    pp::MouseInputEvent event_leave(pp::MouseInputEvent(
        owner()->GetInstance(),
        PP_INPUTEVENT_TYPE_MOUSELEAVE,
        event.GetTimeStamp(),
        event.GetModifiers(),
        mouse_event.GetButton(),
        mouse_event.GetPosition(),
        mouse_event.GetClickCount(),
        mouse_event.GetMovement()));
    return NotifyControls(event_leave);
  }

  return NotifyControls(event);
}

void FadingControls::OnTimerFired(uint32 timer_id) {
  if (timer_id == fading_timer_id_) {
    int32 current_alpha = static_cast<int32>(current_transparency_);
    if (state_ == FADING_IN)
      current_alpha += alpha_shift_;
    else if (state_ == FADING_OUT)
      current_alpha -= alpha_shift_;

    if (current_alpha >= kOpaqueAlpha) {
      state_ = NONE;
      current_alpha = kOpaqueAlpha;
    } else if (current_alpha <= kTransparentAlpha) {
      state_ = NONE;
      current_alpha = kTransparentAlpha;
    }
    current_transparency_ = static_cast<uint8>(current_alpha);

    // Invalidate controls with new alpha transparency.
    std::list<Control*>::iterator iter;
    for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
      // We are going to invalidate the whole FadingControls area, to
      // allow simultaneous drawing.
      (*iter)->AdjustTransparency(current_transparency_, false);
    }
    owner()->Invalidate(id(), GetControlsRect());

    if (state_ != NONE)  // Fading still in progress.
      fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
    else
      OnFadingComplete();
  } else {
    // Dispatch timer to controls.
    std::list<Control*>::iterator iter;
    for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
      (*iter)->OnTimerFired(timer_id);
    }
  }
}

void FadingControls::EventCaptureReleased() {
  if (current_capture_control_ != kInvalidControlId) {
    // Remove previous catpure.
    Control* ctrl = GetControl(current_capture_control_);
    if (ctrl)
      ctrl->EventCaptureReleased();
  }
}

void FadingControls::MoveBy(const pp::Point& offset, bool invalidate) {
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    // We invalidate entire FadingControl later if needed.
    (*iter)->MoveBy(offset, false);
  }
  Control::MoveBy(offset, invalidate);
}

void FadingControls::OnEvent(uint32 control_id, uint32 event_id, void* data) {
  owner()->OnEvent(control_id, event_id, data);
}

void FadingControls::Invalidate(uint32 control_id, const pp::Rect& rc) {
  owner()->Invalidate(control_id, rc);
}

uint32 FadingControls::ScheduleTimer(uint32 control_id, uint32 timeout_ms) {
  // TODO(gene): implement timer routine properly.
  NOTIMPLEMENTED();
  //owner()->ScheduleTimer(control_id);
  return 0;
}

void FadingControls::SetEventCapture(uint32 control_id, bool set_capture) {
  if (control_id == current_capture_control_) {
    if (!set_capture)  // Remove event capture.
      current_capture_control_ = kInvalidControlId;
  } else {
    EventCaptureReleased();
    current_capture_control_ = control_id;
  }
}

void FadingControls::SetCursor(uint32 control_id,
                               PP_CursorType_Dev cursor_type) {
  owner()->SetCursor(control_id, cursor_type);
}

pp::Instance* FadingControls::GetInstance() {
  return owner()->GetInstance();
}

bool FadingControls::AddControl(Control* control) {
  DCHECK(control);
  if (control->owner() != this)
    return false;
  if (!rect().Contains(control->rect()))
    return false;

  control->AdjustTransparency(current_transparency_, false);
  controls_.push_back(control);
  return true;
}

void FadingControls::RemoveControl(uint32 control_id) {
  if (current_capture_control_ == control_id) {
    current_capture_control_ = kInvalidControlId;
  }
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    if ((*iter)->id() == control_id) {
      delete (*iter);
      controls_.erase(iter);
      break;
    }
  }
}

Control* FadingControls::GetControl(uint32 id) {
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    if ((*iter)->id() == id)
      return *iter;
  }
  return NULL;
}

pp::Rect FadingControls::GetControlsRect() {
  pp::Rect rc;
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    rc = rc.Union((*iter)->rect());
  }
  return rc;
}

bool FadingControls::ExpandLeft(int offset) {
  pp::Rect rc = rect();
  rc.set_width(rc.width() + offset);
  rc.set_x(rc.x() - offset);
  if (!rc.Contains(GetControlsRect()))
    return false;
  // No need to invalidate since we are expanding triggering area only.
  SetRect(rc, false);
  return true;
}

void FadingControls::Splash(uint32 time_ms) {
  splash_ = true;
  splash_timeout_ = time_ms;
  alpha_shift_ = kSplashFadingAlphaShift;
  FadeIn();
}

bool FadingControls::NotifyControls(const pp::InputEvent& event) {
  // First pass event to a control that current capture is set to.
  Control* ctrl = GetControl(current_capture_control_);
  if (ctrl) {
    if (ctrl->HandleEvent(event))
      return true;
  }

  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    // Now pass event to all control except control with capture,
    // since we already passed to it above.
    if ((*iter) != ctrl && (*iter)->HandleEvent(event))
      return true;
  }
  return false;
}

void FadingControls::FadeIn() {
  bool already_visible =
      (state_ == NONE && current_transparency_ == kOpaqueAlpha);
  if (state_ != FADING_IN && !already_visible) {
    state_ = FADING_IN;
    fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
  }
  if (already_visible)
    OnFadingComplete();
}

void FadingControls::FadeOut() {
  bool already_invisible =
      (state_ == NONE && current_transparency_ == kTransparentAlpha);
  if (state_ != FADING_OUT && !already_invisible) {
    state_ = FADING_OUT;
    fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
  }
  if (already_invisible)
    OnFadingComplete();
}

void FadingControls::OnFadingComplete() {
  DCHECK(current_transparency_ == kOpaqueAlpha ||
      current_transparency_ == kTransparentAlpha);
  // In the splash mode following states are possible:
  // Fade-in complete: splash_==true, splash_timeout_ != 0
  //   We need to schedule timer for splash_timeout_.
  // Splash timeout complete: splash_==true, splash_timeout_ == 0
  //   We need to fade out still using splash settings.
  // Fade-out complete: current_transparency_ == kTransparentAlpha
  //   We need to cancel splash mode and go back to normal settings.
  if (splash_) {
    if (current_transparency_ == kOpaqueAlpha) {
      if (splash_timeout_) {
        fading_timer_id_ = owner()->ScheduleTimer(id(), splash_timeout_);
        splash_timeout_ = 0;
      } else {
        FadeOut();
      }
    } else {
      CancelSplashMode();
    }
  }
}

void FadingControls::CancelSplashMode() {
  splash_ = false;
  alpha_shift_ = kFadingAlphaShift;
}

}  // namespace chrome_pdf