<commit_before>// Copyright (C) 2012-2017 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/Decoration.hpp"
#include "TestFixtures/SimpleObject.hpp"
#include <autowiring/AnySharedPointer.h>
#include <autowiring/autowiring.h>

class AnySharedPointerTest:
  public testing::Test
{};

// Autowiring takes advantage of the representational equivalence of instantiations of
// shared_ptr, and therefore requires that their layouts all be the same.
static_assert(
  sizeof(std::shared_ptr<void*>) == sizeof(std::shared_ptr<int>),
  "Shared pointer representations must be equivalent for casting to work correctly"
);

TEST_F(AnySharedPointerTest, CanReinterpretCastSharedPtr) {
  auto iShared = std::make_shared<int>(101);
  auto vShared = *reinterpret_cast<std::shared_ptr<void>*>(&iShared);

  ASSERT_EQ(2UL, iShared.use_count()) << "Reinterpretive assignment of a void pointer did not increment the use count";
  ASSERT_EQ(iShared.get(), vShared.get()) << "Reinterpreted shared pointer did not properly hold a member variable";
}

class MyUnusedClass {};

TEST_F(AnySharedPointerTest, OperatorEq) {
  AutoRequired<SimpleObject> sobj;

  // Trivial equivalence of an AnySharedPointer based on an AutoFilter instance
  AnySharedPointer sobjAny1(sobj);
  ASSERT_TRUE((bool)sobjAny1);
  ASSERT_EQ(sobj, sobjAny1) << "An AnySharedPointer instance initialized by constructor violated an identity test";

  // Trivial equivalence of an AnySharedPointer based on an AutoFilter instance
  AnySharedPointer sobjAny2;
  sobjAny2 = sobj;
  ASSERT_TRUE((bool)sobjAny2);
  ASSERT_EQ(sobj, sobjAny2) << "An AnySharedPointer instance initialized by assignment violated an identity test";
}

TEST_F(AnySharedPointerTest, AnySharedPointerRelease) {
  auto t = std::make_shared<int>(5);

  // Assign over, then reset
  {
    AnySharedPointer ptr;
    ptr = t;
  }

  // Verify the AnySharedPointer destructor worked correctly
  ASSERT_TRUE(t.unique()) << "AnySharedPointer instance did not properly release a reference when destroyed";
}

TEST_F(AnySharedPointerTest, SlotReassignment) {
  auto sharedPointerA = std::make_shared<bool>();
  auto sharedPointerB = std::make_shared<bool>();
  auto sharedPointerC = std::make_shared<int>();

  // Make our slot, and start off with a shared pointer of one type:
  AnySharedPointer slot;
  slot = sharedPointerA;

  // Verify that the assignment worked as anticipated:
  ASSERT_EQ(2, sharedPointerA.use_count()) << "Constructor did not properly addref a shared pointer on initialization";

  // Recast to another shared pointer, verify reference count goes down:
  slot = sharedPointerB;
  ASSERT_EQ(2, sharedPointerB.use_count()) << "Reference count was not incremented properly during a shared pointer hold";
  ASSERT_TRUE(sharedPointerA.unique()) << "Destructor was not properly invoked for a shared pointer slot";

  // Now change the type completely, verify proper release:
  slot = sharedPointerC;
  ASSERT_TRUE(sharedPointerB.unique()) << "Second assigned shared pointer was not released under type transformation";
}

TEST_F(AnySharedPointerTest, SlotsInVector) {
  auto sharedPtr = std::make_shared<bool>();

  {
    std::list<AnySharedPointer> slots;

    // Initialize with a lot of copies of sharedPtr
    for(size_t i = 0; i < 10; i++) {
      slots.push_back(AnySharedPointer(sharedPtr));
      ASSERT_EQ(1 + (long)slots.size(), sharedPtr.use_count()) << "Unexpected number of references to a slotted shared pointer";
    }
  }

  // Now verify that we're unique again:
  ASSERT_TRUE(sharedPtr.unique()) << "Slots in a vector did not properly release all local clones";
}

TEST_F(AnySharedPointerTest, SlotDuplication) {
  auto sharedPtr = std::make_shared<bool>();

  AnySharedPointer slot2;

  {
    // Create a base slot to hold the shared pointer:
    AnySharedPointer slot1(sharedPtr);
    ASSERT_FALSE(slot1.empty()) << "A slot initialized from a shared pointer was incorrectly marked as empty";

    // Verify the type came across:
    ASSERT_EQ(auto_id_t<bool>{}, slot1.type()) << "Dynamic initialization did not correctly adjust the dynamic type";

    // Now copy it over:
    slot2 = slot1;

    // Verify reference count was affected as expected
    ASSERT_EQ(3, sharedPtr.use_count()) << "A second-order slot copy didn't increment the reference count as expected";
  }

  // Verify that the slot still holds a reference and that the reference count is correct:
  ASSERT_FALSE(slot2.empty()) << "A slot should have continued to hold a shared pointer, but was prematurely cleared";
  ASSERT_EQ(2, sharedPtr.use_count()) << "A slot going out of scope did not correctly decrement a shared pointer reference";
}

TEST_F(AnySharedPointerTest, TrivialRelease) {
  auto a = std::make_shared<bool>();
  auto b = std::make_shared<int>();

  // Assign the slot to two different values, and make sure that they are released properly
  AnySharedPointer slot;
  slot = a;
  slot = b;

  ASSERT_TRUE(a.unique()) << "Expected reassignment of a slot to release a formerly held instance";
  ASSERT_FALSE(b.unique()) << "Expected slot to hold a reference to the second specified instance";

  // Now release, and verify that a release actually took place
  slot.reset();
  ASSERT_TRUE(b.unique()) << "Releasing a slot did not actually release the held value as expected";
}

TEST_F(AnySharedPointerTest, NoMultipleDelete) {
  auto a = std::make_shared<bool>();
  std::weak_ptr<bool> b = a;

  // Create a slot and validate the behavior of reset, and to ensure that the underlying
  // SharedPointerSlot is not multiply deleted.
  {
    AnySharedPointer slot;
    slot = a;
    slot.reset();
  }

  // Now verify that we didn't accidentally overdecrement the count:
  ASSERT_FALSE(b.expired()) << "Shared pointer prematurely expired; SharedPointerSlot dtor double-strike suspected";
}

TEST_F(AnySharedPointerTest, InitDerivesCorrectType) {
  AnySharedPointer slot;
  slot.init<int>();

  ASSERT_EQ(auto_id_t<int>{}, slot.type()) << "A manually initialized slot did not have the expected type";
}

TEST_F(AnySharedPointerTest, VoidReturnExpected) {
  // Fill out our slot:
  auto v = std::make_shared<int>(5);
  AnySharedPointer slot;
  slot = v;

  // Validate equivalence of the void operator:
  ASSERT_EQ(v.get(), slot.ptr()) << "Shared pointer slot did not return a void* with an expected value";
}

TEST_F(AnySharedPointerTest, CanHoldCoreObject) {
  auto co = std::make_shared<CoreObject>();

  AnySharedPointer x = co;
  ASSERT_EQ(co, x) << "Held CoreObject was not equivalent to constructed instance";
}

TEST_F(AnySharedPointerTest, CanFastCastToSelf) {
  (void)autowiring::fast_pointer_cast_initializer<CoreObject, CoreObject>::sc_init;

  auto co = std::make_shared<CoreObject>();
  ASSERT_EQ(
    co,
    autowiring::fast_pointer_cast<CoreObject>(co)
  ) << "Could not cast a CoreObject instance to itself";
}

class AlternateBase {
public:
  virtual ~AlternateBase(void) {}
};

class AnySharedPtrObjA:
  public CoreObject
{
public:
  int aVal = 101;
  int aVal2 = 101;
};

class AnySharedPtrObjB:
  public AlternateBase,
  public Decoration<0>,
  public AnySharedPtrObjA
{
public:
  int bVal = 102;
};

TEST_F(AnySharedPointerTest, CanCrossCast) {
  (void) auto_id_t_init<AnySharedPtrObjA>::init;
  (void) auto_id_t_init<AnySharedPtrObjB>::init;

  // Ensure that dynamic casters are non-null in the block:
  auto nullCaster = &autowiring::null_cast<AnySharedPtrObjA, CoreObject>;
  ASSERT_NE(
    nullCaster,
    (autowiring::fast_pointer_cast_blind<AnySharedPtrObjA, CoreObject>::cast)
  ) << "Fast pointer caster for AnySharedPtrObjA was not correctly initialized";
  ASSERT_NE(
    reinterpret_cast<std::shared_ptr<void>(*)(const std::shared_ptr<CoreObject>&)>(nullCaster),
    auto_id_t<AnySharedPtrObjA>::s_block.pFromObj
  ) << "AnySharedPtrObjA dynamic caster was incorrectly assigned";

  auto rootB = std::make_shared<AnySharedPtrObjB>();
  auto rootA = std::static_pointer_cast<AnySharedPtrObjA>(rootB);
  auto rootBPtr = rootB.get();
  auto rootAPtr = static_cast<AnySharedPtrObjA*>(rootB.get());
  ASSERT_NE((void*) rootBPtr, (void*) rootAPtr) << "Objects were not correctly detected as having separate offsets";

  AnySharedPointer aASP = rootA;
  std::shared_ptr<CoreObject> obj = aASP.as_obj();
  ASSERT_NE(nullptr, obj) << "An object cast attempt did not succeed as expected";
  ASSERT_EQ(101, aASP.as<AnySharedPtrObjA>()->aVal);

  AnySharedPointer bASP;
  bASP.init<AnySharedPtrObjB>();
  bASP.try_assign(obj);

  ASSERT_NE(bASP, nullptr) << "An attempted cast incorrectly resulted in a null return";
  ASSERT_EQ(102, bASP.as<AnySharedPtrObjB>()->bVal);
  ASSERT_EQ(aASP, bASP) << "An aliased shared pointer was not detected as being equal";
}

TEST_F(AnySharedPointerTest, NullAfterMove) {
  auto ptr = std::make_shared<bool>(false);
  AnySharedPointer p1 = ptr;
  AnySharedPointer p2 = std::move(p1);
  ASSERT_FALSE(p1) << "Move construction of AnySharedPointer did not nullify rhs";
  AnySharedPointer p3;
  p3 = std::move(p2);
  ASSERT_FALSE(p2) << "Move assignment of AnySharedPointer did not nullify rhs";
}

TEST_F(AnySharedPointerTest, NullPtrConstruction) {
  AnySharedPointer x{ nullptr };
  ASSERT_EQ(auto_id_t<void>{}, auto_id{}) << "Default auto_id is expected to be void";
  ASSERT_EQ(auto_id_t<void>{}, x.type()) << "nullptr type_id should have been void";

  AnySharedPointer y;
  AnySharedPointer z;
  y = nullptr;

  ASSERT_EQ(x, y) << "Nullptr initialization was not null";
  ASSERT_EQ(x, z) << "Nullptr assignment was not null";
  ASSERT_EQ(auto_id_t<void>{}, x.type());
  ASSERT_EQ(auto_id_t<void>{}, y.type());
  ASSERT_EQ(auto_id_t<void>{}, z.type());
}

TEST_F(AnySharedPointerTest, VoidSharedPointer) {
  auto p = std::make_shared<int>(101);
  AnySharedPointer x = p;
  ASSERT_EQ(std::static_pointer_cast<void>(p), x.as_void()) << "Void cast of shared pointer did not hold the expected value";
}
<commit_msg>Fix compiler warning on Mac<commit_after>// Copyright (C) 2012-2017 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "TestFixtures/Decoration.hpp"
#include "TestFixtures/SimpleObject.hpp"
#include <autowiring/AnySharedPointer.h>
#include <autowiring/autowiring.h>

class AnySharedPointerTest:
  public testing::Test
{};

// Autowiring takes advantage of the representational equivalence of instantiations of
// shared_ptr, and therefore requires that their layouts all be the same.
static_assert(
  sizeof(std::shared_ptr<void*>) == sizeof(std::shared_ptr<int>),
  "Shared pointer representations must be equivalent for casting to work correctly"
);

TEST_F(AnySharedPointerTest, CanReinterpretCastSharedPtr) {
  auto iShared = std::make_shared<int>(101);
  auto vShared = *reinterpret_cast<std::shared_ptr<void>*>(&iShared);

  ASSERT_EQ(2UL, iShared.use_count()) << "Reinterpretive assignment of a void pointer did not increment the use count";
  ASSERT_EQ(iShared.get(), vShared.get()) << "Reinterpreted shared pointer did not properly hold a member variable";
}

class MyUnusedClass {};

TEST_F(AnySharedPointerTest, OperatorEq) {
  AutoRequired<SimpleObject> sobj;

  // Trivial equivalence of an AnySharedPointer based on an AutoFilter instance
  AnySharedPointer sobjAny1(sobj);
  ASSERT_TRUE((bool)sobjAny1);
  ASSERT_EQ(sobj, sobjAny1) << "An AnySharedPointer instance initialized by constructor violated an identity test";

  // Trivial equivalence of an AnySharedPointer based on an AutoFilter instance
  AnySharedPointer sobjAny2;
  sobjAny2 = sobj;
  ASSERT_TRUE((bool)sobjAny2);
  ASSERT_EQ(sobj, sobjAny2) << "An AnySharedPointer instance initialized by assignment violated an identity test";
}

TEST_F(AnySharedPointerTest, AnySharedPointerRelease) {
  auto t = std::make_shared<int>(5);

  // Assign over, then reset
  {
    AnySharedPointer ptr;
    ptr = t;
  }

  // Verify the AnySharedPointer destructor worked correctly
  ASSERT_TRUE(t.unique()) << "AnySharedPointer instance did not properly release a reference when destroyed";
}

TEST_F(AnySharedPointerTest, SlotReassignment) {
  auto sharedPointerA = std::make_shared<bool>();
  auto sharedPointerB = std::make_shared<bool>();
  auto sharedPointerC = std::make_shared<int>();

  // Make our slot, and start off with a shared pointer of one type:
  AnySharedPointer slot;
  slot = sharedPointerA;

  // Verify that the assignment worked as anticipated:
  ASSERT_EQ(2, sharedPointerA.use_count()) << "Constructor did not properly addref a shared pointer on initialization";

  // Recast to another shared pointer, verify reference count goes down:
  slot = sharedPointerB;
  ASSERT_EQ(2, sharedPointerB.use_count()) << "Reference count was not incremented properly during a shared pointer hold";
  ASSERT_TRUE(sharedPointerA.unique()) << "Destructor was not properly invoked for a shared pointer slot";

  // Now change the type completely, verify proper release:
  slot = sharedPointerC;
  ASSERT_TRUE(sharedPointerB.unique()) << "Second assigned shared pointer was not released under type transformation";
}

TEST_F(AnySharedPointerTest, SlotsInVector) {
  auto sharedPtr = std::make_shared<bool>();

  {
    std::list<AnySharedPointer> slots;

    // Initialize with a lot of copies of sharedPtr
    for(size_t i = 0; i < 10; i++) {
      slots.push_back(AnySharedPointer(sharedPtr));
      ASSERT_EQ(1 + (long)slots.size(), sharedPtr.use_count()) << "Unexpected number of references to a slotted shared pointer";
    }
  }

  // Now verify that we're unique again:
  ASSERT_TRUE(sharedPtr.unique()) << "Slots in a vector did not properly release all local clones";
}

TEST_F(AnySharedPointerTest, SlotDuplication) {
  auto sharedPtr = std::make_shared<bool>();

  AnySharedPointer slot2;

  {
    // Create a base slot to hold the shared pointer:
    AnySharedPointer slot1(sharedPtr);
    ASSERT_FALSE(slot1.empty()) << "A slot initialized from a shared pointer was incorrectly marked as empty";

    // Verify the type came across:
    ASSERT_EQ(auto_id_t<bool>{}, slot1.type()) << "Dynamic initialization did not correctly adjust the dynamic type";

    // Now copy it over:
    slot2 = slot1;

    // Verify reference count was affected as expected
    ASSERT_EQ(3, sharedPtr.use_count()) << "A second-order slot copy didn't increment the reference count as expected";
  }

  // Verify that the slot still holds a reference and that the reference count is correct:
  ASSERT_FALSE(slot2.empty()) << "A slot should have continued to hold a shared pointer, but was prematurely cleared";
  ASSERT_EQ(2, sharedPtr.use_count()) << "A slot going out of scope did not correctly decrement a shared pointer reference";
}

TEST_F(AnySharedPointerTest, TrivialRelease) {
  auto a = std::make_shared<bool>();
  auto b = std::make_shared<int>();

  // Assign the slot to two different values, and make sure that they are released properly
  AnySharedPointer slot;
  slot = a;
  slot = b;

  ASSERT_TRUE(a.unique()) << "Expected reassignment of a slot to release a formerly held instance";
  ASSERT_FALSE(b.unique()) << "Expected slot to hold a reference to the second specified instance";

  // Now release, and verify that a release actually took place
  slot.reset();
  ASSERT_TRUE(b.unique()) << "Releasing a slot did not actually release the held value as expected";
}

TEST_F(AnySharedPointerTest, NoMultipleDelete) {
  auto a = std::make_shared<bool>();
  std::weak_ptr<bool> b = a;

  // Create a slot and validate the behavior of reset, and to ensure that the underlying
  // SharedPointerSlot is not multiply deleted.
  {
    AnySharedPointer slot;
    slot = a;
    slot.reset();
  }

  // Now verify that we didn't accidentally overdecrement the count:
  ASSERT_FALSE(b.expired()) << "Shared pointer prematurely expired; SharedPointerSlot dtor double-strike suspected";
}

TEST_F(AnySharedPointerTest, InitDerivesCorrectType) {
  AnySharedPointer slot;
  slot.init<int>();

  ASSERT_EQ(auto_id_t<int>{}, slot.type()) << "A manually initialized slot did not have the expected type";
}

TEST_F(AnySharedPointerTest, VoidReturnExpected) {
  // Fill out our slot:
  auto v = std::make_shared<int>(5);
  AnySharedPointer slot;
  slot = v;

  // Validate equivalence of the void operator:
  ASSERT_EQ(v.get(), slot.ptr()) << "Shared pointer slot did not return a void* with an expected value";
}

TEST_F(AnySharedPointerTest, CanHoldCoreObject) {
  auto co = std::make_shared<CoreObject>();

  AnySharedPointer x = co;
  ASSERT_EQ(co, x) << "Held CoreObject was not equivalent to constructed instance";
}

template<> const autowiring::fast_pointer_cast_initializer<CoreObject, CoreObject> autowiring::fast_pointer_cast_initializer<CoreObject, CoreObject>::sc_init;

TEST_F(AnySharedPointerTest, CanFastCastToSelf) {
  (void)autowiring::fast_pointer_cast_initializer<CoreObject, CoreObject>::sc_init;

  auto co = std::make_shared<CoreObject>();
  ASSERT_EQ(
    co,
    autowiring::fast_pointer_cast<CoreObject>(co)
  ) << "Could not cast a CoreObject instance to itself";
}

class AlternateBase {
public:
  virtual ~AlternateBase(void) {}
};

class AnySharedPtrObjA:
  public CoreObject
{
public:
  int aVal = 101;
  int aVal2 = 101;
};

class AnySharedPtrObjB:
  public AlternateBase,
  public Decoration<0>,
  public AnySharedPtrObjA
{
public:
  int bVal = 102;
};

TEST_F(AnySharedPointerTest, CanCrossCast) {
  (void) auto_id_t_init<AnySharedPtrObjA>::init;
  (void) auto_id_t_init<AnySharedPtrObjB>::init;

  // Ensure that dynamic casters are non-null in the block:
  auto nullCaster = &autowiring::null_cast<AnySharedPtrObjA, CoreObject>;
  ASSERT_NE(
    nullCaster,
    (autowiring::fast_pointer_cast_blind<AnySharedPtrObjA, CoreObject>::cast)
  ) << "Fast pointer caster for AnySharedPtrObjA was not correctly initialized";
  ASSERT_NE(
    reinterpret_cast<std::shared_ptr<void>(*)(const std::shared_ptr<CoreObject>&)>(nullCaster),
    auto_id_t<AnySharedPtrObjA>::s_block.pFromObj
  ) << "AnySharedPtrObjA dynamic caster was incorrectly assigned";

  auto rootB = std::make_shared<AnySharedPtrObjB>();
  auto rootA = std::static_pointer_cast<AnySharedPtrObjA>(rootB);
  auto rootBPtr = rootB.get();
  auto rootAPtr = static_cast<AnySharedPtrObjA*>(rootB.get());
  ASSERT_NE((void*) rootBPtr, (void*) rootAPtr) << "Objects were not correctly detected as having separate offsets";

  AnySharedPointer aASP = rootA;
  std::shared_ptr<CoreObject> obj = aASP.as_obj();
  ASSERT_NE(nullptr, obj) << "An object cast attempt did not succeed as expected";
  ASSERT_EQ(101, aASP.as<AnySharedPtrObjA>()->aVal);

  AnySharedPointer bASP;
  bASP.init<AnySharedPtrObjB>();
  bASP.try_assign(obj);

  ASSERT_NE(bASP, nullptr) << "An attempted cast incorrectly resulted in a null return";
  ASSERT_EQ(102, bASP.as<AnySharedPtrObjB>()->bVal);
  ASSERT_EQ(aASP, bASP) << "An aliased shared pointer was not detected as being equal";
}

TEST_F(AnySharedPointerTest, NullAfterMove) {
  auto ptr = std::make_shared<bool>(false);
  AnySharedPointer p1 = ptr;
  AnySharedPointer p2 = std::move(p1);
  ASSERT_FALSE(p1) << "Move construction of AnySharedPointer did not nullify rhs";
  AnySharedPointer p3;
  p3 = std::move(p2);
  ASSERT_FALSE(p2) << "Move assignment of AnySharedPointer did not nullify rhs";
}

TEST_F(AnySharedPointerTest, NullPtrConstruction) {
  AnySharedPointer x{ nullptr };
  ASSERT_EQ(auto_id_t<void>{}, auto_id{}) << "Default auto_id is expected to be void";
  ASSERT_EQ(auto_id_t<void>{}, x.type()) << "nullptr type_id should have been void";

  AnySharedPointer y;
  AnySharedPointer z;
  y = nullptr;

  ASSERT_EQ(x, y) << "Nullptr initialization was not null";
  ASSERT_EQ(x, z) << "Nullptr assignment was not null";
  ASSERT_EQ(auto_id_t<void>{}, x.type());
  ASSERT_EQ(auto_id_t<void>{}, y.type());
  ASSERT_EQ(auto_id_t<void>{}, z.type());
}

TEST_F(AnySharedPointerTest, VoidSharedPointer) {
  auto p = std::make_shared<int>(101);
  AnySharedPointer x = p;
  ASSERT_EQ(std::static_pointer_cast<void>(p), x.as_void()) << "Void cast of shared pointer did not hold the expected value";
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/user_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/rounded_view.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
#include "gfx/rect.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/controls/button/text_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/link.h"
#include "views/painter.h"

namespace {

// Background color and corner radius of the login status label and
// signout button.
const SkColor kSignoutBackgroundColor = 0xFF007700;
const int kSignoutBackgroundCornerRadius = 4;

// Horiz/Vert insets for Signout view.
const int kSignoutViewHorizontalInsets = 10;
const int kSignoutViewVerticalInsets = 5;

// Padding between remove button and top right image corner.
const int kRemoveButtonPadding = 3;

// Draws green-ish background for signout view with
// rounded corners at the bottom.
class SignoutBackgroundPainter : public views::Painter {
  virtual void Paint(int w, int h, gfx::Canvas* canvas) {
    SkRect rect = {0, 0, w, h};
    SkPath path;
    SkScalar corners[] = {
      0, 0,
      0, 0,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
    };
    path.addRoundRect(rect, corners);
    SkPaint paint;
    paint.setStyle(SkPaint::kFill_Style);
    paint.setFlags(SkPaint::kAntiAlias_Flag);
    paint.setColor(kSignoutBackgroundColor);
    canvas->AsCanvasSkia()->drawPath(path, paint);
  }
};

}  // namespace

namespace chromeos {

using login::kBackgroundColor;
using login::kTextColor;
using login::kUserImageSize;

// The view that shows the Sign out button below the user's image.
class SignoutView : public views::View {
 public:
  explicit SignoutView(views::LinkController* link_controller) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    const gfx::Font& font = rb.GetFont(ResourceBundle::SmallFont);

    active_user_label_ = new views::Label(
        l10n_util::GetString(IDS_SCREEN_LOCK_ACTIVE_USER));
    active_user_label_->SetFont(font);
    active_user_label_->SetColor(kTextColor);

    signout_link_ = new views::Link(
        l10n_util::GetString(IDS_SCREEN_LOCK_SIGN_OUT));
    signout_link_->SetController(link_controller);
    signout_link_->SetFont(font);
    signout_link_->SetColor(kTextColor);
    signout_link_->SetFocusable(true);

    AddChildView(active_user_label_);
    AddChildView(signout_link_);

    set_background(views::Background::CreateBackgroundPainter(
        true, new SignoutBackgroundPainter()));
  }

  // views::View overrides.
  virtual void Layout() {
    gfx::Size label = active_user_label_->GetPreferredSize();
    gfx::Size button = signout_link_->GetPreferredSize();
    active_user_label_->SetBounds(
        kSignoutViewHorizontalInsets, (height() - label.height()) / 2,
        label.width(), label.height());
    signout_link_->SetBounds(
        width() - button.width() - kSignoutViewHorizontalInsets,
        (height() - button.height()) / 2,
        button.width(), button.height());
  }

  virtual gfx::Size GetPreferredSize() {
    gfx::Size label = active_user_label_->GetPreferredSize();
    gfx::Size button = signout_link_->GetPreferredSize();
    return gfx::Size(label.width() + button.width(),
                     std::max(label.height(), button.height()) +
                     kSignoutViewVerticalInsets * 2);
  }

  views::Link* signout_link() { return signout_link_; }

 private:
  friend class UserView;

  views::Label* active_user_label_;
  views::Link* signout_link_;

  DISALLOW_COPY_AND_ASSIGN(SignoutView);
};

class RemoveButton : public views::TextButton {
 public:
  RemoveButton(views::ButtonListener* listener,
               const SkBitmap& icon,
               const std::wstring& text,
               const gfx::Point& top_right)
    : views::TextButton(listener, std::wstring()),
      icon_(icon),
      text_(text),
      top_right_(top_right),
      was_first_click_(false) {
    SetEnabledColor(SK_ColorWHITE);
    SetDisabledColor(SK_ColorWHITE);
    SetHighlightColor(SK_ColorWHITE);
    SetHoverColor(SK_ColorWHITE);
    SetIcon(icon_);
    UpdatePosition();
  }

 protected:
  // Overridden from View:
  virtual void OnMouseExited(const views::MouseEvent& event) {
    SetIcon(icon_);
    views::TextButton::SetText(std::wstring());
    ClearMaxTextSize();
    set_background(NULL);
    set_border(new views::TextButtonBorder);
    UpdatePosition();
    views::TextButton::OnMouseExited(event);
    was_first_click_ = false;
  }

  void NotifyClick(const views::Event& event) {
    if (!was_first_click_) {
      // On first click transform image to "remove" label.
      SetIcon(SkBitmap());
      views::TextButton::SetText(text_);

      const SkColor kStrokeColor = SK_ColorWHITE;
      const SkColor kButtonColor = 0xFFE94949;
      const int kStrokeWidth = 1;
      const int kVerticalPadding = 4;
      const int kHorizontalPadding = 8;
      const int kCornerRadius = 4;

      set_background(
          CreateRoundedBackground(
              kCornerRadius, kStrokeWidth, kButtonColor, kStrokeColor));

      set_border(
          views::Border::CreateEmptyBorder(kVerticalPadding,
                                           kHorizontalPadding,
                                           kVerticalPadding,
                                           kHorizontalPadding));

      UpdatePosition();
      was_first_click_ = true;
    } else {
      // On second click propagate to base class to fire ButtonPressed.
      views::TextButton::NotifyClick(event);
    }
  }

  void SetText(const std::wstring& text) {
    text_ = text;
  }

 private:
  // Update button position and schedule paint event for the view and parent.
  void UpdatePosition() {
    gfx::Size size = GetPreferredSize();
    gfx::Point origin = top_right_;
    origin.Offset(-size.width(), 0);
    SetBounds(gfx::Rect(origin, size));

    if (GetParent())
      GetParent()->SchedulePaint();
  }

  SkBitmap icon_;
  std::wstring text_;
  gfx::Point top_right_;
  bool was_first_click_;

  DISALLOW_COPY_AND_ASSIGN(RemoveButton);
};

class PodImageView : public views::ImageView {
 public:
  PodImageView() { }

  void SetImage(const SkBitmap& image, const SkBitmap& image_hot) {
    image_ = image;
    image_hot_ = image_hot;
    views::ImageView::SetImage(image_);
  }

 protected:
  // Overridden from View:
  virtual void OnMouseEntered(const views::MouseEvent& event) {
    views::ImageView::SetImage(image_hot_);
  }

  virtual void OnMouseExited(const views::MouseEvent& event) {
    views::ImageView::SetImage(image_);
  }

 private:
  SkBitmap image_;
  SkBitmap image_hot_;

  DISALLOW_COPY_AND_ASSIGN(PodImageView);
};

UserView::UserView(Delegate* delegate, bool is_login, bool need_background)
    : delegate_(delegate),
      signout_view_(NULL),
      image_view_(NULL),
      remove_button_(NULL) {
  DCHECK(delegate);
  if (!is_login)
    signout_view_ = new SignoutView(this);

  if (need_background)
    image_view_ = new RoundedView<PodImageView>;
  else
    image_view_ = new PodImageView;

  Init(need_background);
}

void UserView::Init(bool need_background) {
  if (need_background) {
    image_view_->set_background(
        views::Background::CreateSolidBackground(kBackgroundColor));
  }

  // UserView's layout never changes, so let's layout once here.
  image_view_->SetBounds(0, 0, kUserImageSize, kUserImageSize);
  AddChildView(image_view_);

  if (signout_view_) {
    signout_view_->SetBounds(0, kUserImageSize, kUserImageSize,
                             signout_view_->GetPreferredSize().height());
    AddChildView(signout_view_);
  }

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  remove_button_ = new RemoveButton(
      this,
      *rb.GetBitmapNamed(IDR_CLOSE_BAR_H),
      l10n_util::GetString(IDS_LOGIN_REMOVE),
      gfx::Point(kUserImageSize - kRemoveButtonPadding, kRemoveButtonPadding));
  remove_button_->SetVisible(false);
  AddChildView(remove_button_);
}

void UserView::SetImage(const SkBitmap& image, const SkBitmap& image_hot) {
  int desired_size = std::min(image.width(), image.height());
  // Desired size is not preserved if it's greater than 75% of kUserImageSize.
  if (desired_size * 4 > 3 * kUserImageSize)
    desired_size = kUserImageSize;
  image_view_->SetImageSize(gfx::Size(desired_size, desired_size));
  image_view_->SetImage(image, image_hot);
}

void UserView::SetTooltipText(const std::wstring& text) {
  DCHECK(image_view_);
  image_view_->SetTooltipText(text);
}

gfx::Size UserView::GetPreferredSize() {
  return gfx::Size(
      kUserImageSize,
      kUserImageSize +
      (signout_view_ ? signout_view_->GetPreferredSize().height() : 0));
}

void UserView::SetSignoutEnabled(bool enabled) {
  DCHECK(signout_view_);
  signout_view_->signout_link_->SetEnabled(enabled);
}

void UserView::LinkActivated(views::Link* source, int event_flags) {
  DCHECK(delegate_);
  DCHECK(signout_view_);
  if (signout_view_->signout_link_ == source)
    delegate_->OnSignout();
}

void UserView::SetRemoveButtonVisible(bool flag) {
  remove_button_->SetVisible(flag);
}

void UserView::ButtonPressed(views::Button* sender, const views::Event& event) {
  DCHECK(delegate_);
  if (remove_button_ == sender)
    delegate_->OnRemoveUser();
}

void UserView::OnLocaleChanged() {
  remove_button_->SetText(l10n_util::GetString(IDS_LOGIN_REMOVE));
}

}  // namespace chromeos
<commit_msg>User pods show hand cursor on hover<commit_after>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/user_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/rounded_view.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
#include "gfx/gtk_util.h"
#include "gfx/rect.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/controls/button/text_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/link.h"
#include "views/painter.h"

namespace {

// Background color and corner radius of the login status label and
// signout button.
const SkColor kSignoutBackgroundColor = 0xFF007700;
const int kSignoutBackgroundCornerRadius = 4;

// Horiz/Vert insets for Signout view.
const int kSignoutViewHorizontalInsets = 10;
const int kSignoutViewVerticalInsets = 5;

// Padding between remove button and top right image corner.
const int kRemoveButtonPadding = 3;

// Draws green-ish background for signout view with
// rounded corners at the bottom.
class SignoutBackgroundPainter : public views::Painter {
  virtual void Paint(int w, int h, gfx::Canvas* canvas) {
    SkRect rect = {0, 0, w, h};
    SkPath path;
    SkScalar corners[] = {
      0, 0,
      0, 0,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
      kSignoutBackgroundCornerRadius,
    };
    path.addRoundRect(rect, corners);
    SkPaint paint;
    paint.setStyle(SkPaint::kFill_Style);
    paint.setFlags(SkPaint::kAntiAlias_Flag);
    paint.setColor(kSignoutBackgroundColor);
    canvas->AsCanvasSkia()->drawPath(path, paint);
  }
};

}  // namespace

namespace chromeos {

using login::kBackgroundColor;
using login::kTextColor;
using login::kUserImageSize;

// The view that shows the Sign out button below the user's image.
class SignoutView : public views::View {
 public:
  explicit SignoutView(views::LinkController* link_controller) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    const gfx::Font& font = rb.GetFont(ResourceBundle::SmallFont);

    active_user_label_ = new views::Label(
        l10n_util::GetString(IDS_SCREEN_LOCK_ACTIVE_USER));
    active_user_label_->SetFont(font);
    active_user_label_->SetColor(kTextColor);

    signout_link_ = new views::Link(
        l10n_util::GetString(IDS_SCREEN_LOCK_SIGN_OUT));
    signout_link_->SetController(link_controller);
    signout_link_->SetFont(font);
    signout_link_->SetColor(kTextColor);
    signout_link_->SetFocusable(true);

    AddChildView(active_user_label_);
    AddChildView(signout_link_);

    set_background(views::Background::CreateBackgroundPainter(
        true, new SignoutBackgroundPainter()));
  }

  // views::View overrides.
  virtual void Layout() {
    gfx::Size label = active_user_label_->GetPreferredSize();
    gfx::Size button = signout_link_->GetPreferredSize();
    active_user_label_->SetBounds(
        kSignoutViewHorizontalInsets, (height() - label.height()) / 2,
        label.width(), label.height());
    signout_link_->SetBounds(
        width() - button.width() - kSignoutViewHorizontalInsets,
        (height() - button.height()) / 2,
        button.width(), button.height());
  }

  virtual gfx::Size GetPreferredSize() {
    gfx::Size label = active_user_label_->GetPreferredSize();
    gfx::Size button = signout_link_->GetPreferredSize();
    return gfx::Size(label.width() + button.width(),
                     std::max(label.height(), button.height()) +
                     kSignoutViewVerticalInsets * 2);
  }

  views::Link* signout_link() { return signout_link_; }

 private:
  friend class UserView;

  views::Label* active_user_label_;
  views::Link* signout_link_;

  DISALLOW_COPY_AND_ASSIGN(SignoutView);
};

class RemoveButton : public views::TextButton {
 public:
  RemoveButton(views::ButtonListener* listener,
               const SkBitmap& icon,
               const std::wstring& text,
               const gfx::Point& top_right)
    : views::TextButton(listener, std::wstring()),
      icon_(icon),
      text_(text),
      top_right_(top_right),
      was_first_click_(false) {
    SetEnabledColor(SK_ColorWHITE);
    SetDisabledColor(SK_ColorWHITE);
    SetHighlightColor(SK_ColorWHITE);
    SetHoverColor(SK_ColorWHITE);
    SetIcon(icon_);
    UpdatePosition();
  }

 protected:
  // Overridden from View:
  virtual void OnMouseExited(const views::MouseEvent& event) {
    SetIcon(icon_);
    views::TextButton::SetText(std::wstring());
    ClearMaxTextSize();
    set_background(NULL);
    set_border(new views::TextButtonBorder);
    UpdatePosition();
    views::TextButton::OnMouseExited(event);
    was_first_click_ = false;
  }

  void NotifyClick(const views::Event& event) {
    if (!was_first_click_) {
      // On first click transform image to "remove" label.
      SetIcon(SkBitmap());
      views::TextButton::SetText(text_);

      const SkColor kStrokeColor = SK_ColorWHITE;
      const SkColor kButtonColor = 0xFFE94949;
      const int kStrokeWidth = 1;
      const int kVerticalPadding = 4;
      const int kHorizontalPadding = 8;
      const int kCornerRadius = 4;

      set_background(
          CreateRoundedBackground(
              kCornerRadius, kStrokeWidth, kButtonColor, kStrokeColor));

      set_border(
          views::Border::CreateEmptyBorder(kVerticalPadding,
                                           kHorizontalPadding,
                                           kVerticalPadding,
                                           kHorizontalPadding));

      UpdatePosition();
      was_first_click_ = true;
    } else {
      // On second click propagate to base class to fire ButtonPressed.
      views::TextButton::NotifyClick(event);
    }
  }

  void SetText(const std::wstring& text) {
    text_ = text;
  }

 private:
  // Update button position and schedule paint event for the view and parent.
  void UpdatePosition() {
    gfx::Size size = GetPreferredSize();
    gfx::Point origin = top_right_;
    origin.Offset(-size.width(), 0);
    SetBounds(gfx::Rect(origin, size));

    if (GetParent())
      GetParent()->SchedulePaint();
  }

  SkBitmap icon_;
  std::wstring text_;
  gfx::Point top_right_;
  bool was_first_click_;

  DISALLOW_COPY_AND_ASSIGN(RemoveButton);
};

class PodImageView : public views::ImageView {
 public:
  PodImageView() { }

  void SetImage(const SkBitmap& image, const SkBitmap& image_hot) {
    image_ = image;
    image_hot_ = image_hot;
    views::ImageView::SetImage(image_);
  }

 protected:
  // Overridden from View:
  virtual void OnMouseEntered(const views::MouseEvent& event) {
    views::ImageView::SetImage(image_hot_);
  }

  virtual void OnMouseExited(const views::MouseEvent& event) {
    views::ImageView::SetImage(image_);
  }

  gfx::NativeCursor GetCursorForPoint(
      views::Event::EventType event_type,
      const gfx::Point& p) {
    return gfx::GetCursor(GDK_HAND2);
  }

 private:
  SkBitmap image_;
  SkBitmap image_hot_;

  DISALLOW_COPY_AND_ASSIGN(PodImageView);
};

UserView::UserView(Delegate* delegate, bool is_login, bool need_background)
    : delegate_(delegate),
      signout_view_(NULL),
      image_view_(NULL),
      remove_button_(NULL) {
  DCHECK(delegate);
  if (!is_login)
    signout_view_ = new SignoutView(this);

  if (need_background)
    image_view_ = new RoundedView<PodImageView>;
  else
    image_view_ = new PodImageView;

  Init(need_background);
}

void UserView::Init(bool need_background) {
  if (need_background) {
    image_view_->set_background(
        views::Background::CreateSolidBackground(kBackgroundColor));
  }

  // UserView's layout never changes, so let's layout once here.
  image_view_->SetBounds(0, 0, kUserImageSize, kUserImageSize);
  AddChildView(image_view_);

  if (signout_view_) {
    signout_view_->SetBounds(0, kUserImageSize, kUserImageSize,
                             signout_view_->GetPreferredSize().height());
    AddChildView(signout_view_);
  }

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  remove_button_ = new RemoveButton(
      this,
      *rb.GetBitmapNamed(IDR_CLOSE_BAR_H),
      l10n_util::GetString(IDS_LOGIN_REMOVE),
      gfx::Point(kUserImageSize - kRemoveButtonPadding, kRemoveButtonPadding));
  remove_button_->SetVisible(false);
  AddChildView(remove_button_);
}

void UserView::SetImage(const SkBitmap& image, const SkBitmap& image_hot) {
  int desired_size = std::min(image.width(), image.height());
  // Desired size is not preserved if it's greater than 75% of kUserImageSize.
  if (desired_size * 4 > 3 * kUserImageSize)
    desired_size = kUserImageSize;
  image_view_->SetImageSize(gfx::Size(desired_size, desired_size));
  image_view_->SetImage(image, image_hot);
}

void UserView::SetTooltipText(const std::wstring& text) {
  DCHECK(image_view_);
  image_view_->SetTooltipText(text);
}

gfx::Size UserView::GetPreferredSize() {
  return gfx::Size(
      kUserImageSize,
      kUserImageSize +
      (signout_view_ ? signout_view_->GetPreferredSize().height() : 0));
}

void UserView::SetSignoutEnabled(bool enabled) {
  DCHECK(signout_view_);
  signout_view_->signout_link_->SetEnabled(enabled);
}

void UserView::LinkActivated(views::Link* source, int event_flags) {
  DCHECK(delegate_);
  DCHECK(signout_view_);
  if (signout_view_->signout_link_ == source)
    delegate_->OnSignout();
}

void UserView::SetRemoveButtonVisible(bool flag) {
  remove_button_->SetVisible(flag);
}

void UserView::ButtonPressed(views::Button* sender, const views::Event& event) {
  DCHECK(delegate_);
  if (remove_button_ == sender)
    delegate_->OnRemoveUser();
}

void UserView::OnLocaleChanged() {
  remove_button_->SetText(l10n_util::GetString(IDS_LOGIN_REMOVE));
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "chrome/browser/chromeos/update_observer.h"

#include "app/l10n_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace chromeos {

UpdateObserver::UpdateObserver(Profile* profile)
    : notification_(profile, "update.chromeos", IDR_NOTIFICATION_UPDATE,
                    l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)),
      progress_(-1) {}

UpdateObserver::~UpdateObserver() {
  notification_.Hide();
}

void UpdateObserver::UpdateStatusChanged(UpdateLibrary* library) {
  switch (library->status().status) {
    case UPDATE_STATUS_IDLE:
    case UPDATE_STATUS_CHECKING_FOR_UPDATE:
      // Do nothing in these cases, we don't want to notify the user of the
      // check unless there is an update. We don't hide here because
      // we want the final state to be sticky.
      break;
    case UPDATE_STATUS_UPDATE_AVAILABLE:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE),
                         false);
      break;
    case UPDATE_STATUS_DOWNLOADING:
    {
      int progress = static_cast<int>(library->status().download_progress *
          100.0);
      if (progress != progress_) {
        progress_ = progress;
        notification_.Show(l10n_util::GetStringFUTF16(IDS_UPDATE_DOWNLOADING,
            base::IntToString16(progress_)), false);
      }
    }
      break;
    case UPDATE_STATUS_VERIFYING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING),
                         false);
      break;
    case UPDATE_STATUS_FINALIZING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING),
                         false);
      break;
    case UPDATE_STATUS_UPDATED_NEED_REBOOT:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
      break;
    default:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      break;
  }
}

}  // namespace chromeos
<commit_msg>Handle the REPORTING_ERROR_EVENT state appropriately.<commit_after>// Copyright (c) 2010 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 "chrome/browser/chromeos/update_observer.h"

#include "app/l10n_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace chromeos {

UpdateObserver::UpdateObserver(Profile* profile)
    : notification_(profile, "update.chromeos", IDR_NOTIFICATION_UPDATE,
                    l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)),
      progress_(-1) {}

UpdateObserver::~UpdateObserver() {
  notification_.Hide();
}

void UpdateObserver::UpdateStatusChanged(UpdateLibrary* library) {
  switch (library->status().status) {
    case UPDATE_STATUS_IDLE:
    case UPDATE_STATUS_CHECKING_FOR_UPDATE:
      // Do nothing in these cases, we don't want to notify the user of the
      // check unless there is an update. We don't hide here because
      // we want the final state to be sticky.
      break;
    case UPDATE_STATUS_UPDATE_AVAILABLE:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE),
                         false);
      break;
    case UPDATE_STATUS_DOWNLOADING:
    {
      int progress = static_cast<int>(library->status().download_progress *
          100.0);
      if (progress != progress_) {
        progress_ = progress;
        notification_.Show(l10n_util::GetStringFUTF16(IDS_UPDATE_DOWNLOADING,
            base::IntToString16(progress_)), false);
      }
    }
      break;
    case UPDATE_STATUS_VERIFYING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING),
                         false);
      break;
    case UPDATE_STATUS_FINALIZING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING),
                         false);
      break;
    case UPDATE_STATUS_UPDATED_NEED_REBOOT:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
      break;
    case UPDATE_STATUS_REPORTING_ERROR_EVENT:
      // If the update engine encounters an error and we have already
      // notified the user of the update progress, show an error
      // notification. Don't show anything otherwise -- for example,
      // in cases where the update engine encounters an error while
      // checking for an update.
      if (notification_.visible()) {
        notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      }
      break;
    default:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      break;
  }
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2009 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 "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

const std::wstring DevToolsWindow::kDevToolsApp = L"DevToolsApp";

// static
TabContents* DevToolsWindow::GetDevToolsContents(TabContents* inspected_tab) {
  if (!inspected_tab) {
    return NULL;
  }

  if (!DevToolsManager::GetInstance())
    return NULL;  // Happens only in tests.

  DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(inspected_tab->render_view_host());
  if (!client_host) {
    return NULL;
  }

  DevToolsWindow* window = client_host->AsDevToolsWindow();
  if (!window || !window->is_docked()) {
    return NULL;
  }
  return window->tab_contents();
}

DevToolsWindow::DevToolsWindow(Profile* profile,
                               RenderViewHost* inspected_rvh,
                               bool docked)
    : profile_(profile),
      browser_(NULL),
      docked_(docked),
      is_loaded_(false),
      action_on_load_(DEVTOOLS_TOGGLE_ACTION_NONE) {
  // Create TabContents with devtools.
  tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
  tab_contents_->render_view_host()->AllowBindings(BindingsPolicy::DOM_UI);
  tab_contents_->controller().LoadURL(
      GetDevToolsUrl(), GURL(), PageTransition::START_PAGE);

  // Wipe out page icon so that the default application icon is used.
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  entry->favicon().set_bitmap(SkBitmap());
  entry->favicon().set_is_valid(true);

  // Register on-load actions.
  registrar_.Add(this,
                 NotificationType::LOAD_STOP,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this,
                 NotificationType::TAB_CLOSING,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
                 NotificationService::AllSources());
  inspected_tab_ = inspected_rvh->delegate()->GetAsTabContents();
}

DevToolsWindow::~DevToolsWindow() {
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::InspectedTabClosing() {
  if (docked_) {
    // Update dev tools to reflect removed dev tools window.

    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
    // In case of docked tab_contents we own it, so delete here.
    delete tab_contents_;

    delete this;
  } else {
    // First, initiate self-destruct to free all the registrars.
    // Then close all tabs. Browser will take care of deleting tab_contents
    // for us.
    Browser* browser = browser_;
    delete this;
    browser->CloseAllTabs();
  }
}

void DevToolsWindow::Show(DevToolsToggleAction action) {
  if (docked_) {
    // Just tell inspected browser to update splitter.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      tab_contents_->set_delegate(this);
      inspected_window->UpdateDevTools();
      SetAttachedWindow();
      tab_contents_->view()->SetInitialFocus();
      ScheduleAction(action);
      return;
    } else {
      // Sometimes we don't know where to dock. Stay undocked.
      docked_ = false;
    }
  }

  if (!browser_)
    CreateDevToolsBrowser();

  // Avoid consecutive window switching if the devtools window has been opened
  // and the Inspect Element shortcut is pressed in the inspected tab.
  bool should_show_window =
      !browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;
  if (should_show_window)
    browser_->window()->Show();
  SetAttachedWindow();
  if (should_show_window)
    tab_contents_->view()->SetInitialFocus();

  ScheduleAction(action);
}

void DevToolsWindow::Activate() {
  if (!docked_) {
    if (!browser_->window()->IsActive()) {
      browser_->window()->Activate();
    }
  } else {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      tab_contents_->view()->Focus();
  }
}

void DevToolsWindow::SetDocked(bool docked) {
  if (docked_ == docked)
    return;
  if (docked && !GetInspectedBrowserWindow()) {
    // Cannot dock, avoid window flashing due to close-reopen cycle.
    return;
  }
  docked_ = docked;

  if (docked) {
    // Detach window from the external devtools browser. It will lead to
    // the browser object's close and delete. Remove observer first.
    TabStripModel* tabstrip_model = browser_->tabstrip_model();
    tabstrip_model->DetachTabContentsAt(
        tabstrip_model->GetIndexOfTabContents(tab_contents_));
    browser_ = NULL;
  } else {
    // Update inspected window to hide split and reset it.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      inspected_window->UpdateDevTools();
      inspected_window = NULL;
    }
  }
  Show(DEVTOOLS_TOGGLE_ACTION_NONE);
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::CreateDevToolsBrowser() {
  // TODO(pfeldman): Make browser's getter for this key static.
  std::wstring wp_key = L"";
  wp_key.append(prefs::kBrowserWindowPlacement);
  wp_key.append(L"_");
  wp_key.append(kDevToolsApp);

  PrefService* prefs = g_browser_process->local_state();
  if (!prefs->FindPreference(wp_key.c_str())) {
    prefs->RegisterDictionaryPref(wp_key.c_str());
  }

  const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
  if (!wp_pref) {
    DictionaryValue* defaults = prefs->GetMutableDictionary(wp_key.c_str());
    defaults->SetInteger(L"left", 100);
    defaults->SetInteger(L"top", 100);
    defaults->SetInteger(L"right", 740);
    defaults->SetInteger(L"bottom", 740);
    defaults->SetBoolean(L"maximized", false);
    defaults->SetBoolean(L"always_on_top", false);
  }

  browser_ = Browser::CreateForDevTools(profile_);
  browser_->tabstrip_model()->AddTabContents(
      tab_contents_, -1, PageTransition::START_PAGE,
      TabStripModel::ADD_SELECTED);
}

BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
  for (BrowserList::const_iterator it = BrowserList::begin();
       it != BrowserList::end(); ++it) {
    Browser* browser = *it;
    for (int i = 0; i < browser->tab_count(); ++i) {
      TabContents* tab_contents = browser->GetTabContentsAt(i);
      if (tab_contents == inspected_tab_) {
        return browser->window();
      }
    }
  }
  return NULL;
}

void DevToolsWindow::SetAttachedWindow() {
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(
          L"", docked_ ? L"WebInspector.setAttachedWindow(true);" :
                         L"WebInspector.setAttachedWindow(false);");
}

void DevToolsWindow::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == NotificationType::LOAD_STOP) {
    SetAttachedWindow();
    is_loaded_ = true;
    UpdateTheme();
    DoAction();
  } else if (type == NotificationType::TAB_CLOSING) {
    if (Source<NavigationController>(source).ptr() ==
            &tab_contents_->controller()) {
      // This happens when browser closes all of its tabs as a result
      // of window.Close event.
      // Notify manager that this DevToolsClientHost no longer exists and
      // initiate self-destuct here.
      NotifyCloseListener();
      delete this;
    }
  } else if (type == NotificationType::BROWSER_THEME_CHANGED) {
    UpdateTheme();
  }
}

void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
  action_on_load_ = action;
  if (is_loaded_)
    DoAction();
}

void DevToolsWindow::DoAction() {
  // TODO: these messages should be pushed through the WebKit API instead.
  switch (action_on_load_) {
    case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(L"", L"WebInspector.showConsole();");
      break;
    case DEVTOOLS_TOGGLE_ACTION_INSPECT:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(
              L"", L"WebInspector.toggleSearchingForNode();");
    case DEVTOOLS_TOGGLE_ACTION_NONE:
      // Do nothing.
      break;
    default:
      NOTREACHED();
  }
  action_on_load_ = DEVTOOLS_TOGGLE_ACTION_NONE;
}

std::string SkColorToRGBAString(SkColor color) {
  // We convert the alpha using DoubleToString because StringPrintf will use
  // locale specific formatters (e.g., use , instead of . in German).
  return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
      SkColorGetG(color), SkColorGetB(color),
      DoubleToString(SkColorGetA(color) / 255.0).c_str());
}

GURL DevToolsWindow::GetDevToolsUrl() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);

  std::string url_string = StringPrintf(
      "%sdevtools.html?docked=%s&toolbar_color=%s&text_color=%s",
      chrome::kChromeUIDevToolsURL,
      docked_ ? "true" : "false",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  return GURL(url_string);
}

void DevToolsWindow::UpdateTheme() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
  std::string command = StringPrintf(
      "WebInspector.setToolbarColors(\"%s\", \"%s\")",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(L"", UTF8ToWide(command));
}

bool DevToolsWindow::PreHandleKeyboardEvent(
    const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      return inspected_window->PreHandleKeyboardEvent(
          event, is_keyboard_shortcut);
  }
  return false;
}

void DevToolsWindow::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->HandleKeyboardEvent(event);
  }
}
<commit_msg>Show DevTools window when the Inspect shortcut is hit for the first time<commit_after>// Copyright (c) 2009 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 "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

const std::wstring DevToolsWindow::kDevToolsApp = L"DevToolsApp";

// static
TabContents* DevToolsWindow::GetDevToolsContents(TabContents* inspected_tab) {
  if (!inspected_tab) {
    return NULL;
  }

  if (!DevToolsManager::GetInstance())
    return NULL;  // Happens only in tests.

  DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(inspected_tab->render_view_host());
  if (!client_host) {
    return NULL;
  }

  DevToolsWindow* window = client_host->AsDevToolsWindow();
  if (!window || !window->is_docked()) {
    return NULL;
  }
  return window->tab_contents();
}

DevToolsWindow::DevToolsWindow(Profile* profile,
                               RenderViewHost* inspected_rvh,
                               bool docked)
    : profile_(profile),
      browser_(NULL),
      docked_(docked),
      is_loaded_(false),
      action_on_load_(DEVTOOLS_TOGGLE_ACTION_NONE) {
  // Create TabContents with devtools.
  tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
  tab_contents_->render_view_host()->AllowBindings(BindingsPolicy::DOM_UI);
  tab_contents_->controller().LoadURL(
      GetDevToolsUrl(), GURL(), PageTransition::START_PAGE);

  // Wipe out page icon so that the default application icon is used.
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  entry->favicon().set_bitmap(SkBitmap());
  entry->favicon().set_is_valid(true);

  // Register on-load actions.
  registrar_.Add(this,
                 NotificationType::LOAD_STOP,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this,
                 NotificationType::TAB_CLOSING,
                 Source<NavigationController>(&tab_contents_->controller()));
  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
                 NotificationService::AllSources());
  inspected_tab_ = inspected_rvh->delegate()->GetAsTabContents();
}

DevToolsWindow::~DevToolsWindow() {
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::InspectedTabClosing() {
  if (docked_) {
    // Update dev tools to reflect removed dev tools window.

    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
    // In case of docked tab_contents we own it, so delete here.
    delete tab_contents_;

    delete this;
  } else {
    // First, initiate self-destruct to free all the registrars.
    // Then close all tabs. Browser will take care of deleting tab_contents
    // for us.
    Browser* browser = browser_;
    delete this;
    browser->CloseAllTabs();
  }
}

void DevToolsWindow::Show(DevToolsToggleAction action) {
  if (docked_) {
    // Just tell inspected browser to update splitter.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      tab_contents_->set_delegate(this);
      inspected_window->UpdateDevTools();
      SetAttachedWindow();
      tab_contents_->view()->SetInitialFocus();
      ScheduleAction(action);
      return;
    } else {
      // Sometimes we don't know where to dock. Stay undocked.
      docked_ = false;
    }
  }

  // Avoid consecutive window switching if the devtools window has been opened
  // and the Inspect Element shortcut is pressed in the inspected tab.
  bool should_show_window =
      !browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;

  if (!browser_)
    CreateDevToolsBrowser();

  if (should_show_window)
    browser_->window()->Show();
  SetAttachedWindow();
  if (should_show_window)
    tab_contents_->view()->SetInitialFocus();

  ScheduleAction(action);
}

void DevToolsWindow::Activate() {
  if (!docked_) {
    if (!browser_->window()->IsActive()) {
      browser_->window()->Activate();
    }
  } else {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      tab_contents_->view()->Focus();
  }
}

void DevToolsWindow::SetDocked(bool docked) {
  if (docked_ == docked)
    return;
  if (docked && !GetInspectedBrowserWindow()) {
    // Cannot dock, avoid window flashing due to close-reopen cycle.
    return;
  }
  docked_ = docked;

  if (docked) {
    // Detach window from the external devtools browser. It will lead to
    // the browser object's close and delete. Remove observer first.
    TabStripModel* tabstrip_model = browser_->tabstrip_model();
    tabstrip_model->DetachTabContentsAt(
        tabstrip_model->GetIndexOfTabContents(tab_contents_));
    browser_ = NULL;
  } else {
    // Update inspected window to hide split and reset it.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      inspected_window->UpdateDevTools();
      inspected_window = NULL;
    }
  }
  Show(DEVTOOLS_TOGGLE_ACTION_NONE);
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::CreateDevToolsBrowser() {
  // TODO(pfeldman): Make browser's getter for this key static.
  std::wstring wp_key = L"";
  wp_key.append(prefs::kBrowserWindowPlacement);
  wp_key.append(L"_");
  wp_key.append(kDevToolsApp);

  PrefService* prefs = g_browser_process->local_state();
  if (!prefs->FindPreference(wp_key.c_str())) {
    prefs->RegisterDictionaryPref(wp_key.c_str());
  }

  const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
  if (!wp_pref) {
    DictionaryValue* defaults = prefs->GetMutableDictionary(wp_key.c_str());
    defaults->SetInteger(L"left", 100);
    defaults->SetInteger(L"top", 100);
    defaults->SetInteger(L"right", 740);
    defaults->SetInteger(L"bottom", 740);
    defaults->SetBoolean(L"maximized", false);
    defaults->SetBoolean(L"always_on_top", false);
  }

  browser_ = Browser::CreateForDevTools(profile_);
  browser_->tabstrip_model()->AddTabContents(
      tab_contents_, -1, PageTransition::START_PAGE,
      TabStripModel::ADD_SELECTED);
}

BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
  for (BrowserList::const_iterator it = BrowserList::begin();
       it != BrowserList::end(); ++it) {
    Browser* browser = *it;
    for (int i = 0; i < browser->tab_count(); ++i) {
      TabContents* tab_contents = browser->GetTabContentsAt(i);
      if (tab_contents == inspected_tab_) {
        return browser->window();
      }
    }
  }
  return NULL;
}

void DevToolsWindow::SetAttachedWindow() {
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(
          L"", docked_ ? L"WebInspector.setAttachedWindow(true);" :
                         L"WebInspector.setAttachedWindow(false);");
}

void DevToolsWindow::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == NotificationType::LOAD_STOP) {
    SetAttachedWindow();
    is_loaded_ = true;
    UpdateTheme();
    DoAction();
  } else if (type == NotificationType::TAB_CLOSING) {
    if (Source<NavigationController>(source).ptr() ==
            &tab_contents_->controller()) {
      // This happens when browser closes all of its tabs as a result
      // of window.Close event.
      // Notify manager that this DevToolsClientHost no longer exists and
      // initiate self-destuct here.
      NotifyCloseListener();
      delete this;
    }
  } else if (type == NotificationType::BROWSER_THEME_CHANGED) {
    UpdateTheme();
  }
}

void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
  action_on_load_ = action;
  if (is_loaded_)
    DoAction();
}

void DevToolsWindow::DoAction() {
  // TODO: these messages should be pushed through the WebKit API instead.
  switch (action_on_load_) {
    case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(L"", L"WebInspector.showConsole();");
      break;
    case DEVTOOLS_TOGGLE_ACTION_INSPECT:
      tab_contents_->render_view_host()->
          ExecuteJavascriptInWebFrame(
              L"", L"WebInspector.toggleSearchingForNode();");
    case DEVTOOLS_TOGGLE_ACTION_NONE:
      // Do nothing.
      break;
    default:
      NOTREACHED();
  }
  action_on_load_ = DEVTOOLS_TOGGLE_ACTION_NONE;
}

std::string SkColorToRGBAString(SkColor color) {
  // We convert the alpha using DoubleToString because StringPrintf will use
  // locale specific formatters (e.g., use , instead of . in German).
  return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
      SkColorGetG(color), SkColorGetB(color),
      DoubleToString(SkColorGetA(color) / 255.0).c_str());
}

GURL DevToolsWindow::GetDevToolsUrl() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);

  std::string url_string = StringPrintf(
      "%sdevtools.html?docked=%s&toolbar_color=%s&text_color=%s",
      chrome::kChromeUIDevToolsURL,
      docked_ ? "true" : "false",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  return GURL(url_string);
}

void DevToolsWindow::UpdateTheme() {
  BrowserThemeProvider* tp = profile_->GetThemeProvider();
  CHECK(tp);

  SkColor color_toolbar =
      tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
  SkColor color_tab_text =
      tp->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
  std::string command = StringPrintf(
      "WebInspector.setToolbarColors(\"%s\", \"%s\")",
      SkColorToRGBAString(color_toolbar).c_str(),
      SkColorToRGBAString(color_tab_text).c_str());
  tab_contents_->render_view_host()->
      ExecuteJavascriptInWebFrame(L"", UTF8ToWide(command));
}

bool DevToolsWindow::PreHandleKeyboardEvent(
    const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      return inspected_window->PreHandleKeyboardEvent(
          event, is_keyboard_shortcut);
  }
  return false;
}

void DevToolsWindow::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  if (docked_) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->HandleKeyboardEvent(event);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "chrome/browser/net/load_timing_observer.h"

#include "base/time.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/common/resource_response.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_netlog_params.h"

using base::Time;
using base::TimeTicks;
using webkit_glue::ResourceLoaderBridge;
using webkit_glue::ResourceLoadTimingInfo;

const size_t kMaxNumEntries = 1000;

namespace {

// We know that this conversion is not solid and suffers from world clock
// changes, but it should be good enough for the load timing info.
static Time TimeTicksToTime(const TimeTicks& time_ticks) {
  static int64 tick_to_time_offset;
  static bool tick_to_time_offset_available = false;
  if (!tick_to_time_offset_available) {
    int64 cur_time = (Time::Now() - Time()).InMicroseconds();
    int64 cur_time_ticks = (TimeTicks::Now() - TimeTicks()).InMicroseconds();
    // If we add this number to a time tick value, it gives the timestamp.
    tick_to_time_offset = cur_time - cur_time_ticks;
    tick_to_time_offset_available = true;
  }
  return Time::FromInternalValue(time_ticks.ToInternalValue() +
                                 tick_to_time_offset);
}

static int32 TimeTicksToOffset(
    const TimeTicks& time_ticks,
    LoadTimingObserver::URLRequestRecord* record) {
  return static_cast<int32>(
      (time_ticks - record->base_ticks).InMillisecondsRoundedUp());
}

}  // namespace

LoadTimingObserver::URLRequestRecord::URLRequestRecord()
    : connect_job_id(net::NetLog::Source::kInvalidId),
      socket_log_id(net::NetLog::Source::kInvalidId),
      socket_reused(false) {
}

LoadTimingObserver::LoadTimingObserver()
    : ThreadSafeObserver(net::NetLog::LOG_BASIC),
      last_connect_job_id_(net::NetLog::Source::kInvalidId) {
}

LoadTimingObserver::~LoadTimingObserver() {
}

LoadTimingObserver::URLRequestRecord*
LoadTimingObserver::GetURLRequestRecord(uint32 source_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  URLRequestToRecordMap::iterator it = url_request_to_record_.find(source_id);
  if (it != url_request_to_record_.end())
    return &it->second;
  return NULL;
}

void LoadTimingObserver::OnAddEntry(net::NetLog::EventType type,
                                    const base::TimeTicks& time,
                                    const net::NetLog::Source& source,
                                    net::NetLog::EventPhase phase,
                                    net::NetLog::EventParameters* params) {
  // The events that the Observer is interested in only occur on the IO thread.
  if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
    return;
  if (source.type == net::NetLog::SOURCE_URL_REQUEST)
    OnAddURLRequestEntry(type, time, source, phase, params);
  else if (source.type == net::NetLog::SOURCE_CONNECT_JOB)
    OnAddConnectJobEntry(type, time, source, phase, params);
  else if (source.type == net::NetLog::SOURCE_SOCKET)
    OnAddSocketEntry(type, time, source, phase, params);
}

// static
void LoadTimingObserver::PopulateTimingInfo(net::URLRequest* request,
                                            ResourceResponse* response) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING))
    return;

  ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>(
      request->net_log().net_log());
  if (chrome_net_log == NULL)
    return;

  uint32 source_id = request->net_log().source().id;
  LoadTimingObserver* observer = chrome_net_log->load_timing_observer();
  LoadTimingObserver::URLRequestRecord* record =
      observer->GetURLRequestRecord(source_id);
  if (record) {
    response->response_head.connection_id = record->socket_log_id;
    response->response_head.connection_reused = record->socket_reused;
    response->response_head.load_timing = record->timing;
  }
}

void LoadTimingObserver::OnAddURLRequestEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
    if (is_begin) {
      // Only record timing for entries with corresponding flag.
      int load_flags = static_cast<URLRequestStartEventParameters*>(params)->
          load_flags();
      if (!(load_flags & net::LOAD_ENABLE_LOAD_TIMING))
        return;

      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (url_request_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer url request count has grown "
                        "larger than expected, resetting";
        url_request_to_record_.clear();
      }

      URLRequestRecord& record = url_request_to_record_[source.id];
      record.base_ticks = time;
      record.timing.base_time = TimeTicksToTime(time);
    }
    return;
  } else if (type == net::NetLog::TYPE_REQUEST_ALIVE) {
    // Cleanup records based on the TYPE_REQUEST_ALIVE entry.
    if (is_end)
      url_request_to_record_.erase(source.id);
    return;
  }

  URLRequestRecord* record = GetURLRequestRecord(source.id);
  if (!record)
    return;

  ResourceLoadTimingInfo& timing = record->timing;

  switch (type) {
    case net::NetLog::TYPE_PROXY_SERVICE:
      if (is_begin)
        timing.proxy_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.proxy_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_SOCKET_POOL:
      if (is_begin)
        timing.connect_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.connect_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB:
      {
        uint32 connect_job_id = static_cast<net::NetLogSourceParameter*>(
            params)->value().id;
        if (last_connect_job_id_ == connect_job_id &&
            !last_connect_job_record_.dns_start.is_null()) {
          timing.dns_start =
              TimeTicksToOffset(last_connect_job_record_.dns_start, record);
          timing.dns_end =
              TimeTicksToOffset(last_connect_job_record_.dns_end, record);
        }
      }
      break;
    case net::NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET:
      record->socket_reused = true;
      break;
    case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET:
      record->socket_log_id = static_cast<net::NetLogSourceParameter*>(
          params)->value().id;
      if (!record->socket_reused) {
        SocketToRecordMap::iterator it =
            socket_to_record_.find(record->socket_log_id);
        if (it != socket_to_record_.end() && !it->second.ssl_start.is_null()) {
          timing.ssl_start = TimeTicksToOffset(it->second.ssl_start, record);
          timing.ssl_end = TimeTicksToOffset(it->second.ssl_end, record);
        }
      }
      break;
    case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST:
      if (is_begin)
        timing.send_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.send_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS:
      if (is_begin)
        timing.receive_headers_start =  TimeTicksToOffset(time, record);
      else if (is_end)
        timing.receive_headers_end =  TimeTicksToOffset(time, record);
      break;
    default:
      break;
  }
}

void LoadTimingObserver::OnAddConnectJobEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  // Manage record lifetime based on the SOCKET_POOL_CONNECT_JOB entry.
  if (type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB) {
    if (is_begin) {
      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (connect_job_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer connect job count has grown "
                        "larger than expected, resetting";
        connect_job_to_record_.clear();
      }

      connect_job_to_record_.insert(
          std::make_pair(source.id, ConnectJobRecord()));
    } else if (is_end) {
      ConnectJobToRecordMap::iterator it =
          connect_job_to_record_.find(source.id);
      if (it != connect_job_to_record_.end()) {
        last_connect_job_id_ = it->first;
        last_connect_job_record_ = it->second;
        connect_job_to_record_.erase(it);
      }
    }
  } else if (type == net::NetLog::TYPE_HOST_RESOLVER_IMPL) {
    ConnectJobToRecordMap::iterator it =
        connect_job_to_record_.find(source.id);
    if (it != connect_job_to_record_.end()) {
      if (is_begin)
        it->second.dns_start = time;
      else if (is_end)
        it->second.dns_end = time;
    }
  }
}

void LoadTimingObserver::OnAddSocketEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  // Manage record lifetime based on the SOCKET_ALIVE entry.
  if (type == net::NetLog::TYPE_SOCKET_ALIVE) {
    if (is_begin) {
      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (socket_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer socket count has grown "
                        "larger than expected, resetting";
        socket_to_record_.clear();
      }

      socket_to_record_.insert(
          std::make_pair(source.id, SocketRecord()));
    } else if (is_end) {
      socket_to_record_.erase(source.id);
    }
    return;
  }
  SocketToRecordMap::iterator it = socket_to_record_.find(source.id);
  if (it == socket_to_record_.end())
    return;

  if (type == net::NetLog::TYPE_SSL_CONNECT) {
    if (is_begin)
      it->second.ssl_start = time;
    else if (is_end)
      it->second.ssl_end = time;
  }
}
<commit_msg>DevTools: Network requests are timed with 1.6 days.<commit_after>// Copyright (c) 2010 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 "chrome/browser/net/load_timing_observer.h"

#include "base/time.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/common/resource_response.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_netlog_params.h"

using base::Time;
using base::TimeTicks;
using webkit_glue::ResourceLoaderBridge;
using webkit_glue::ResourceLoadTimingInfo;

const size_t kMaxNumEntries = 1000;

namespace {

const int64 kSyncPeriodMicroseconds = 1000 * 1000 * 10;

// We know that this conversion is not solid and suffers from world clock
// changes, but given that we sync clock every 10 seconds, it should be good
// enough for the load timing info.
static Time TimeTicksToTime(const TimeTicks& time_ticks) {
  static int64 tick_to_time_offset;
  static int64 last_sync_ticks = 0;
  if (time_ticks.ToInternalValue() - last_sync_ticks >
          kSyncPeriodMicroseconds) {
    int64 cur_time = (Time::Now() - Time()).InMicroseconds();
    int64 cur_time_ticks = (TimeTicks::Now() - TimeTicks()).InMicroseconds();
    // If we add this number to a time tick value, it gives the timestamp.
    tick_to_time_offset = cur_time - cur_time_ticks;
    last_sync_ticks = time_ticks.ToInternalValue();
  }
  return Time::FromInternalValue(time_ticks.ToInternalValue() +
                                 tick_to_time_offset);
}

static int32 TimeTicksToOffset(
    const TimeTicks& time_ticks,
    LoadTimingObserver::URLRequestRecord* record) {
  return static_cast<int32>(
      (time_ticks - record->base_ticks).InMillisecondsRoundedUp());
}

}  // namespace

LoadTimingObserver::URLRequestRecord::URLRequestRecord()
    : connect_job_id(net::NetLog::Source::kInvalidId),
      socket_log_id(net::NetLog::Source::kInvalidId),
      socket_reused(false) {
}

LoadTimingObserver::LoadTimingObserver()
    : ThreadSafeObserver(net::NetLog::LOG_BASIC),
      last_connect_job_id_(net::NetLog::Source::kInvalidId) {
}

LoadTimingObserver::~LoadTimingObserver() {
}

LoadTimingObserver::URLRequestRecord*
LoadTimingObserver::GetURLRequestRecord(uint32 source_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  URLRequestToRecordMap::iterator it = url_request_to_record_.find(source_id);
  if (it != url_request_to_record_.end())
    return &it->second;
  return NULL;
}

void LoadTimingObserver::OnAddEntry(net::NetLog::EventType type,
                                    const base::TimeTicks& time,
                                    const net::NetLog::Source& source,
                                    net::NetLog::EventPhase phase,
                                    net::NetLog::EventParameters* params) {
  // The events that the Observer is interested in only occur on the IO thread.
  if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
    return;
  if (source.type == net::NetLog::SOURCE_URL_REQUEST)
    OnAddURLRequestEntry(type, time, source, phase, params);
  else if (source.type == net::NetLog::SOURCE_CONNECT_JOB)
    OnAddConnectJobEntry(type, time, source, phase, params);
  else if (source.type == net::NetLog::SOURCE_SOCKET)
    OnAddSocketEntry(type, time, source, phase, params);
}

// static
void LoadTimingObserver::PopulateTimingInfo(net::URLRequest* request,
                                            ResourceResponse* response) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING))
    return;

  ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>(
      request->net_log().net_log());
  if (chrome_net_log == NULL)
    return;

  uint32 source_id = request->net_log().source().id;
  LoadTimingObserver* observer = chrome_net_log->load_timing_observer();
  LoadTimingObserver::URLRequestRecord* record =
      observer->GetURLRequestRecord(source_id);
  if (record) {
    response->response_head.connection_id = record->socket_log_id;
    response->response_head.connection_reused = record->socket_reused;
    response->response_head.load_timing = record->timing;
  }
}

void LoadTimingObserver::OnAddURLRequestEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
    if (is_begin) {
      // Only record timing for entries with corresponding flag.
      int load_flags = static_cast<URLRequestStartEventParameters*>(params)->
          load_flags();
      if (!(load_flags & net::LOAD_ENABLE_LOAD_TIMING))
        return;

      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (url_request_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer url request count has grown "
                        "larger than expected, resetting";
        url_request_to_record_.clear();
      }

      URLRequestRecord& record = url_request_to_record_[source.id];
      record.base_ticks = time;
      record.timing.base_time = TimeTicksToTime(time);
    }
    return;
  } else if (type == net::NetLog::TYPE_REQUEST_ALIVE) {
    // Cleanup records based on the TYPE_REQUEST_ALIVE entry.
    if (is_end)
      url_request_to_record_.erase(source.id);
    return;
  }

  URLRequestRecord* record = GetURLRequestRecord(source.id);
  if (!record)
    return;

  ResourceLoadTimingInfo& timing = record->timing;

  switch (type) {
    case net::NetLog::TYPE_PROXY_SERVICE:
      if (is_begin)
        timing.proxy_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.proxy_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_SOCKET_POOL:
      if (is_begin)
        timing.connect_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.connect_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB:
      {
        uint32 connect_job_id = static_cast<net::NetLogSourceParameter*>(
            params)->value().id;
        if (last_connect_job_id_ == connect_job_id &&
            !last_connect_job_record_.dns_start.is_null()) {
          timing.dns_start =
              TimeTicksToOffset(last_connect_job_record_.dns_start, record);
          timing.dns_end =
              TimeTicksToOffset(last_connect_job_record_.dns_end, record);
        }
      }
      break;
    case net::NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET:
      record->socket_reused = true;
      break;
    case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET:
      record->socket_log_id = static_cast<net::NetLogSourceParameter*>(
          params)->value().id;
      if (!record->socket_reused) {
        SocketToRecordMap::iterator it =
            socket_to_record_.find(record->socket_log_id);
        if (it != socket_to_record_.end() && !it->second.ssl_start.is_null()) {
          timing.ssl_start = TimeTicksToOffset(it->second.ssl_start, record);
          timing.ssl_end = TimeTicksToOffset(it->second.ssl_end, record);
        }
      }
      break;
    case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST:
      if (is_begin)
        timing.send_start = TimeTicksToOffset(time, record);
      else if (is_end)
        timing.send_end = TimeTicksToOffset(time, record);
      break;
    case net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS:
      if (is_begin)
        timing.receive_headers_start =  TimeTicksToOffset(time, record);
      else if (is_end)
        timing.receive_headers_end =  TimeTicksToOffset(time, record);
      break;
    default:
      break;
  }
}

void LoadTimingObserver::OnAddConnectJobEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  // Manage record lifetime based on the SOCKET_POOL_CONNECT_JOB entry.
  if (type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB) {
    if (is_begin) {
      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (connect_job_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer connect job count has grown "
                        "larger than expected, resetting";
        connect_job_to_record_.clear();
      }

      connect_job_to_record_.insert(
          std::make_pair(source.id, ConnectJobRecord()));
    } else if (is_end) {
      ConnectJobToRecordMap::iterator it =
          connect_job_to_record_.find(source.id);
      if (it != connect_job_to_record_.end()) {
        last_connect_job_id_ = it->first;
        last_connect_job_record_ = it->second;
        connect_job_to_record_.erase(it);
      }
    }
  } else if (type == net::NetLog::TYPE_HOST_RESOLVER_IMPL) {
    ConnectJobToRecordMap::iterator it =
        connect_job_to_record_.find(source.id);
    if (it != connect_job_to_record_.end()) {
      if (is_begin)
        it->second.dns_start = time;
      else if (is_end)
        it->second.dns_end = time;
    }
  }
}

void LoadTimingObserver::OnAddSocketEntry(
    net::NetLog::EventType type,
    const base::TimeTicks& time,
    const net::NetLog::Source& source,
    net::NetLog::EventPhase phase,
    net::NetLog::EventParameters* params) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  bool is_begin = phase == net::NetLog::PHASE_BEGIN;
  bool is_end = phase == net::NetLog::PHASE_END;

  // Manage record lifetime based on the SOCKET_ALIVE entry.
  if (type == net::NetLog::TYPE_SOCKET_ALIVE) {
    if (is_begin) {
      // Prevents us from passively growing the memory memory unbounded in case
      // something went wrong. Should not happen.
      if (socket_to_record_.size() > kMaxNumEntries) {
        LOG(WARNING) << "The load timing observer socket count has grown "
                        "larger than expected, resetting";
        socket_to_record_.clear();
      }

      socket_to_record_.insert(
          std::make_pair(source.id, SocketRecord()));
    } else if (is_end) {
      socket_to_record_.erase(source.id);
    }
    return;
  }
  SocketToRecordMap::iterator it = socket_to_record_.find(source.id);
  if (it == socket_to_record_.end())
    return;

  if (type == net::NetLog::TYPE_SSL_CONNECT) {
    if (is_begin)
      it->second.ssl_start = time;
    else if (is_end)
      it->second.ssl_end = time;
  }
}
<|endoftext|>