<commit_before>// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_
#define ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_

#include <type_traits>

#include "../../config.hpp"
#include "../../detail/various.hpp"

#include "../../intrinsics.hpp"
#include "../../functional.hpp"

#include "../../warp/warp_sort.hpp"

BEGIN_ROCPRIM_NAMESPACE

namespace detail
{

template<
    class Key,
    unsigned int BlockSize,
    class Value
>
class block_sort_bitonic
{
    template<class KeyType, class ValueType>
    struct storage_type_
    {
        KeyType key[BlockSize];
        ValueType value[BlockSize];
    };

    template<class KeyType>
    struct storage_type_<KeyType, empty_type>
    {
        KeyType key[BlockSize];
    };

public:
    using storage_type = detail::raw_storage<storage_type_<Key, Value>>;

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        this->sort_impl<BlockSize>(
            ::rocprim::flat_block_thread_id(),
            storage, compare_function,
            thread_key
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              BinaryFunction compare_function)
    {
        ROCPRIM_SHARED_MEMORY storage_type storage;
        this->sort(thread_key, storage, compare_function);
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        this->sort_impl<BlockSize>(
            ::rocprim::flat_block_thread_id(),
            storage, compare_function,
            thread_key, thread_value
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              BinaryFunction compare_function)
    {
        ROCPRIM_SHARED_MEMORY storage_type storage;
        this->sort(thread_key, thread_value, storage, compare_function);
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              storage_type& storage,
              const unsigned int size,
              BinaryFunction compare_function)
    {
        this->sort_impl(
            ::rocprim::flat_block_thread_id(), size,
            storage, compare_function,
            thread_key
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              storage_type& storage,
              const unsigned int size,
              BinaryFunction compare_function)
    {
        this->sort_impl(
            ::rocprim::flat_block_thread_id(), size,
            storage, compare_function,
            thread_key, thread_value
        );
    }

private:
    ROCPRIM_DEVICE inline
    void copy_to_shared(Key& k, const unsigned int flat_tid, storage_type& storage)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        storage_.key[flat_tid] = k;
        ::rocprim::syncthreads();
    }

    ROCPRIM_DEVICE inline
    void copy_to_shared(Key& k, Value& v, const unsigned int flat_tid, storage_type& storage)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        storage_.key[flat_tid] = k;
        storage_.value[flat_tid] = v;
        ::rocprim::syncthreads();
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void swap(Key& key,
              const unsigned int flat_tid,
              const unsigned int next_id,
              const bool dir,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        Key next_key = storage_.key[next_id];
        bool compare = compare_function(next_key, key);
        bool swap = compare ^ (next_id < flat_tid) ^ dir;
        if(swap)
        {
            key = next_key;
        }
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void swap(Key& key,
              Value& value,
              const unsigned int flat_tid,
              const unsigned int next_id,
              const bool dir,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        Key next_key = storage_.key[next_id];
        Value next_value = storage_.value[next_id];
        bool compare = compare_function(next_key, key);
        bool swap = compare ^ (next_id < flat_tid) ^ dir;
        if(swap)
        {
            key = next_key;
            value = next_value;
        }
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<(Size <= ::rocprim::warp_size())>::type
    sort_power_two(const unsigned int flat_tid,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        (void) flat_tid;
        (void) storage;

        ::rocprim::warp_sort<Key, Size, Value> wsort;
        wsort.sort(kv..., compare_function);
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<(Size > ::rocprim::warp_size())>::type
    sort_power_two(const unsigned int flat_tid,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        const auto warp_id_is_even = ((flat_tid / ::rocprim::warp_size()) % 2) == 0;
        ::rocprim::warp_sort<Key, ::rocprim::warp_size(), Value> wsort;
        auto compare_function2 =
            [compare_function, warp_id_is_even](const Key& a, const Key& b) -> bool
            {
                auto r = compare_function(a, b);
                if(warp_id_is_even)
                    return r;
                return !r;
            };
        wsort.sort(kv..., compare_function2);

        #pragma unroll
        for(unsigned int length = ::rocprim::warp_size(); length < Size; length *= 2)
        {
            bool dir = (flat_tid & (length * 2)) != 0;
            for(unsigned int k = length; k > 0; k /= 2)
            {
                copy_to_shared(kv..., flat_tid, storage);
                swap(kv..., flat_tid, flat_tid ^ k, dir, storage, compare_function);
                ::rocprim::syncthreads();
            }
        }
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<detail::is_power_of_two(Size)>::type
    sort_impl(const unsigned int flat_tid,
              storage_type& storage,
              BinaryFunction compare_function,
              KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        sort_power_two<Size, BinaryFunction>(flat_tid, storage, compare_function, kv...);
    }

    // In case BlockSize is not a power-of-two, the slower odd-even mergesort function is used
    // instead of the bitonic sort function
    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<!detail::is_power_of_two(Size)>::type
    sort_impl(const unsigned int flat_tid,
              storage_type& storage,
              BinaryFunction compare_function,
              KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        copy_to_shared(kv..., flat_tid, storage);

        bool is_even = (flat_tid % 2) == 0;
        unsigned int odd_id = (is_even) ? std::max(flat_tid, (unsigned int) 1) - 1 : std::min(flat_tid + 1, Size - 1);
        unsigned int even_id = (is_even) ? std::min(flat_tid + 1, Size - 1) : std::max(flat_tid, (unsigned int) 1) - 1;

        #pragma unroll
        for(unsigned int length = 0; length < Size; length++)
        {
            unsigned int next_id = (length % 2) == 0 ? even_id : odd_id;
            swap(kv..., flat_tid, next_id, 0, storage, compare_function);
            ::rocprim::syncthreads();
            copy_to_shared(kv..., flat_tid, storage);
        }
    }

    template<
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    void sort_impl(const unsigned int flat_tid,
                   const unsigned int size,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        if(size > BlockSize)
        {
            return;
        }

        copy_to_shared(kv..., flat_tid, storage);

        bool is_even = (flat_tid % 2 == 0);
        unsigned int odd_id = (is_even) ? std::max(flat_tid, (unsigned int) 1) - 1 : std::min(flat_tid + 1, size - 1);
        unsigned int even_id = (is_even) ? std::min(flat_tid + 1, size - 1) : std::max(flat_tid, (unsigned int) 1) - 1;

        for(unsigned int length = 0; length < size; length++)
        {
            unsigned int next_id = (length % 2 == 0) ? even_id : odd_id;
            swap(kv..., flat_tid, next_id, 0, storage, compare_function);
            ::rocprim::syncthreads();
            copy_to_shared(kv..., flat_tid, storage);
        }
    }
};

} // end namespace detail

END_ROCPRIM_NAMESPACE

#endif // ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_
<commit_msg>Fix block sort with size specified for comparisons with lookup tables<commit_after>// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_
#define ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_

#include <type_traits>

#include "../../config.hpp"
#include "../../detail/various.hpp"

#include "../../intrinsics.hpp"
#include "../../functional.hpp"

#include "../../warp/warp_sort.hpp"

BEGIN_ROCPRIM_NAMESPACE

namespace detail
{

template<
    class Key,
    unsigned int BlockSize,
    class Value
>
class block_sort_bitonic
{
    template<class KeyType, class ValueType>
    struct storage_type_
    {
        KeyType key[BlockSize];
        ValueType value[BlockSize];
    };

    template<class KeyType>
    struct storage_type_<KeyType, empty_type>
    {
        KeyType key[BlockSize];
    };

public:
    using storage_type = detail::raw_storage<storage_type_<Key, Value>>;

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        this->sort_impl<BlockSize>(
            ::rocprim::flat_block_thread_id(),
            storage, compare_function,
            thread_key
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              BinaryFunction compare_function)
    {
        ROCPRIM_SHARED_MEMORY storage_type storage;
        this->sort(thread_key, storage, compare_function);
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        this->sort_impl<BlockSize>(
            ::rocprim::flat_block_thread_id(),
            storage, compare_function,
            thread_key, thread_value
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              BinaryFunction compare_function)
    {
        ROCPRIM_SHARED_MEMORY storage_type storage;
        this->sort(thread_key, thread_value, storage, compare_function);
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              storage_type& storage,
              const unsigned int size,
              BinaryFunction compare_function)
    {
        this->sort_impl(
            ::rocprim::flat_block_thread_id(), size,
            storage, compare_function,
            thread_key
        );
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void sort(Key& thread_key,
              Value& thread_value,
              storage_type& storage,
              const unsigned int size,
              BinaryFunction compare_function)
    {
        this->sort_impl(
            ::rocprim::flat_block_thread_id(), size,
            storage, compare_function,
            thread_key, thread_value
        );
    }

private:
    ROCPRIM_DEVICE inline
    void copy_to_shared(Key& k, const unsigned int flat_tid, storage_type& storage)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        storage_.key[flat_tid] = k;
        ::rocprim::syncthreads();
    }

    ROCPRIM_DEVICE inline
    void copy_to_shared(Key& k, Value& v, const unsigned int flat_tid, storage_type& storage)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        storage_.key[flat_tid] = k;
        storage_.value[flat_tid] = v;
        ::rocprim::syncthreads();
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void swap(Key& key,
              const unsigned int flat_tid,
              const unsigned int next_id,
              const bool dir,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        Key next_key = storage_.key[next_id];
        bool compare = compare_function(next_key, key);
        bool swap = compare ^ (next_id < flat_tid) ^ dir;
        if(swap)
        {
            key = next_key;
        }
    }

    template<class BinaryFunction>
    ROCPRIM_DEVICE inline
    void swap(Key& key,
              Value& value,
              const unsigned int flat_tid,
              const unsigned int next_id,
              const bool dir,
              storage_type& storage,
              BinaryFunction compare_function)
    {
        storage_type_<Key, Value>& storage_ = storage.get();
        Key next_key = storage_.key[next_id];
        Value next_value = storage_.value[next_id];
        bool compare = compare_function(next_key, key);
        bool swap = compare ^ (next_id < flat_tid) ^ dir;
        if(swap)
        {
            key = next_key;
            value = next_value;
        }
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<(Size <= ::rocprim::warp_size())>::type
    sort_power_two(const unsigned int flat_tid,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        (void) flat_tid;
        (void) storage;

        ::rocprim::warp_sort<Key, Size, Value> wsort;
        wsort.sort(kv..., compare_function);
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<(Size > ::rocprim::warp_size())>::type
    sort_power_two(const unsigned int flat_tid,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        const auto warp_id_is_even = ((flat_tid / ::rocprim::warp_size()) % 2) == 0;
        ::rocprim::warp_sort<Key, ::rocprim::warp_size(), Value> wsort;
        auto compare_function2 =
            [compare_function, warp_id_is_even](const Key& a, const Key& b) -> bool
            {
                auto r = compare_function(a, b);
                if(warp_id_is_even)
                    return r;
                return !r;
            };
        wsort.sort(kv..., compare_function2);

        #pragma unroll
        for(unsigned int length = ::rocprim::warp_size(); length < Size; length *= 2)
        {
            bool dir = (flat_tid & (length * 2)) != 0;
            for(unsigned int k = length; k > 0; k /= 2)
            {
                copy_to_shared(kv..., flat_tid, storage);
                swap(kv..., flat_tid, flat_tid ^ k, dir, storage, compare_function);
                ::rocprim::syncthreads();
            }
        }
    }

    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<detail::is_power_of_two(Size)>::type
    sort_impl(const unsigned int flat_tid,
              storage_type& storage,
              BinaryFunction compare_function,
              KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        sort_power_two<Size, BinaryFunction>(flat_tid, storage, compare_function, kv...);
    }

    // In case BlockSize is not a power-of-two, the slower odd-even mergesort function is used
    // instead of the bitonic sort function
    template<
        unsigned int Size,
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    typename std::enable_if<!detail::is_power_of_two(Size)>::type
    sort_impl(const unsigned int flat_tid,
              storage_type& storage,
              BinaryFunction compare_function,
              KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        copy_to_shared(kv..., flat_tid, storage);

        bool is_even = (flat_tid % 2) == 0;
        unsigned int odd_id = (is_even) ? ::rocprim::max(flat_tid, 1u) - 1 : ::rocprim::min(flat_tid + 1, Size - 1);
        unsigned int even_id = (is_even) ? ::rocprim::min(flat_tid + 1, Size - 1) : ::rocprim::max(flat_tid, 1u) - 1;

        #pragma unroll
        for(unsigned int length = 0; length < Size; length++)
        {
            unsigned int next_id = (length % 2) == 0 ? even_id : odd_id;
            swap(kv..., flat_tid, next_id, 0, storage, compare_function);
            ::rocprim::syncthreads();
            copy_to_shared(kv..., flat_tid, storage);
        }
    }

    template<
        class BinaryFunction,
        class... KeyValue
    >
    ROCPRIM_DEVICE inline
    void sort_impl(const unsigned int flat_tid,
                   const unsigned int size,
                   storage_type& storage,
                   BinaryFunction compare_function,
                   KeyValue&... kv)
    {
        static constexpr unsigned int PairSize =  sizeof...(KeyValue);
        static_assert(
            PairSize < 3,
            "KeyValue parameter pack can 1 or 2 elements (key, or key and value)"
        );

        if(size > BlockSize)
        {
            return;
        }

        copy_to_shared(kv..., flat_tid, storage);

        bool is_even = (flat_tid % 2 == 0);
        unsigned int odd_id = (is_even) ? ::rocprim::max(flat_tid, 1u) - 1 : ::rocprim::min(flat_tid + 1, size - 1);
        unsigned int even_id = (is_even) ? ::rocprim::min(flat_tid + 1, size - 1) : ::rocprim::max(flat_tid, 1u) - 1;

        for(unsigned int length = 0; length < size; length++)
        {
            unsigned int next_id = (length % 2 == 0) ? even_id : odd_id;
            // Use only "valid" keys to ensure that compare_function will not use garbage keys
            // for example, as indices of an array (a lookup table)
            if(flat_tid < size)
            {
                swap(kv..., flat_tid, next_id, 0, storage, compare_function);
            }
            ::rocprim::syncthreads();
            copy_to_shared(kv..., flat_tid, storage);
        }
    }
};

} // end namespace detail

END_ROCPRIM_NAMESPACE

#endif // ROCPRIM_BLOCK_DETAIL_BLOCK_SORT_SHARED_HPP_
<|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.

// Navigates the browser to server and client redirect pages and makes sure
// that the correct redirects are reflected in the history database. Errors
// here might indicate that WebKit changed the calls our glue layer gets in
// the case of redirects. It may also mean problems with the history system.

#include "base/file_util.h"
#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/view_ids.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "views/event.h"

namespace {

class RedirectTest : public UITest {
 public:
  RedirectTest()
      : test_server_(net::TestServer::TYPE_HTTP,
                     FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
  }

 protected:
  net::TestServer test_server_;
};

// Tests a single server redirect
TEST_F(RedirectTest, Server) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec());

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests a single client redirect.
// Flaky: see crbug.com/55380
TEST_F(RedirectTest, FLAKY_Client) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + final_url.spec());

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());

  // The address bar should display the final URL.
  GURL tab_url;
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);

  // Navigate one more time.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  // The address bar should still display the final URL.
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);
}

TEST_F(RedirectTest, ClientEmptyReferer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("file_client_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  std::vector<GURL> redirects;
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests to make sure a location change when a pending redirect exists isn't
// flagged as a redirect.
#if defined(OS_MACOSX)
// SimulateOSClick is broken on the Mac: http://crbug.com/45162
#define MAYBE_ClientCancelled DISABLED_ClientCancelled
#elif defined(OS_WIN)
// http://crbug.com/53091
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#else
#define MAYBE_ClientCancelled ClientCancelled
#endif

TEST_F(RedirectTest, MAYBE_ClientCancelled) {
  FilePath first_path(test_data_directory_);
  first_path = first_path.AppendASCII("cancelled_redirect_test.html");
  ASSERT_TRUE(file_util::AbsolutePath(&first_path));
  GURL first_url = net::FilePathToFileURL(first_path);

  NavigateToURLBlockUntilNavigationsComplete(first_url, 1);

  scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
  ASSERT_TRUE(browser.get());
  scoped_refptr<WindowProxy> window = browser->GetWindow();
  ASSERT_TRUE(window.get());
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  int64 last_nav_time = 0;
  EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time));
  // Simulate a click to force to make a user-initiated location change;
  // otherwise, a non user-initiated in-page location change will be treated
  // as client redirect and the redirect will be recoreded, which can cause
  // this test failed.
  gfx::Rect tab_view_bounds;
  ASSERT_TRUE(browser->BringToFront());
  ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds,
                                    true));
  ASSERT_TRUE(
      window->SimulateOSClick(tab_view_bounds.CenterPoint(),
                              views::Event::EF_LEFT_BUTTON_DOWN));
  EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time));

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  // There should be no redirects from first_url, because the anchor location
  // change that occurs should not be flagged as a redirect and the meta-refresh
  // won't have fired yet.
  ASSERT_EQ(0U, redirects.size());
  GURL current_url;
  ASSERT_TRUE(tab_proxy->GetCurrentURL(&current_url));

  // Need to test final path and ref separately since constructing a file url
  // containing an anchor using FilePathToFileURL will escape the anchor as
  // %23, but in current_url the anchor will be '#'.
  std::string final_ref = "myanchor";
  FilePath current_path;
  ASSERT_TRUE(net::FileURLToFilePath(current_url, &current_path));
  ASSERT_TRUE(file_util::AbsolutePath(&current_path));
  // Path should remain unchanged.
  EXPECT_EQ(StringToLowerASCII(first_path.value()),
            StringToLowerASCII(current_path.value()));
  EXPECT_EQ(final_ref, current_url.ref());
}

// Tests a client->server->server redirect
TEST_F(RedirectTest, ClientServerServer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL next_to_last = test_server_.GetURL(
      "server-redirect?" + final_url.spec());
  GURL second_url = test_server_.GetURL(
      "server-redirect?" + next_to_last.spec());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + second_url.spec());
  std::vector<GURL> redirects;

  // We need the sleep for the client redirects, because it appears as two
  // page visits in the browser.
  NavigateToURL(first_url);

  for (int i = 0; i < 10; ++i) {
    PlatformThread::Sleep(sleep_timeout_ms());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
    if (!redirects.empty())
      break;
  }

  ASSERT_EQ(3U, redirects.size());
  EXPECT_EQ(second_url.spec(), redirects[0].spec());
  EXPECT_EQ(next_to_last.spec(), redirects[1].spec());
  EXPECT_EQ(final_url.spec(), redirects[2].spec());
}

// Tests that the "#reference" gets preserved across server redirects.
TEST_F(RedirectTest, ServerReference) {
  ASSERT_TRUE(test_server_.Start());

  const std::string ref("reference");

  GURL final_url = test_server_.GetURL(std::string());
  GURL initial_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec() + "#" + ref);

  NavigateToURL(initial_url);

  GURL url = GetActiveTabURL();
  EXPECT_EQ(ref, url.ref());
}

// Test that redirect from http:// to file:// :
// A) does not crash the browser or confuse the redirect chain, see bug 1080873
// B) does not take place.
TEST_F(RedirectTest, NoHttpToFile) {
  ASSERT_TRUE(test_server_.Start());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("http_to_file.html");
  GURL file_url = net::FilePathToFileURL(test_file);

  GURL initial_url = test_server_.GetURL(
      "client-redirect?" + file_url.spec());

  NavigateToURL(initial_url);
  // UITest will check for crashes. We make sure the title doesn't match the
  // title from the file, because the nav should not have taken place.
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  std::wstring actual_title;
  ASSERT_TRUE(tab_proxy->GetTabTitle(&actual_title));
  EXPECT_NE("File!", WideToUTF8(actual_title));
}

// Ensures that non-user initiated location changes (within page) are
// flagged as client redirects. See bug 1139823.
TEST_F(RedirectTest, ClientFragments) {
  ASSERT_TRUE(test_server_.Start());

  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("ref_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);
  std::vector<GURL> redirects;

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  EXPECT_EQ(1U, redirects.size());
  EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
}

// TODO(timsteele): This is disabled because our current testserver can't
// handle multiple requests in parallel, making it hang on the first request
// to /slow?60. It's unable to serve our second request for files/title2.html
// until /slow? completes, which doesn't give the desired behavior. We could
// alternatively load the second page from disk, but we would need to start
// the browser for this testcase with --process-per-tab, and I don't think
// we can do this at test-case-level granularity at the moment.
// http://crbug.com/45056
TEST_F(RedirectTest,
       DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
  // We want to initiate a second navigation after the provisional load for
  // the client redirect destination has started, but before this load is
  // committed. To achieve this, we tell the browser to load a slow page,
  // which causes it to start a provisional load, and while it is waiting
  // for the response (which means it hasn't committed the load for the client
  // redirect destination page yet), we issue a new navigation request.
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL("files/title2.html");
  GURL slow = test_server_.GetURL("slow?60");
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + slow.spec());
  std::vector<GURL> redirects;

  NavigateToURL(first_url);
  // We don't sleep here - the first navigation won't have been committed yet
  // because we told the server to wait a minute. This means the browser has
  // started it's provisional load for the client redirect destination page but
  // hasn't completed. Our time is now!
  NavigateToURL(final_url);

  std::wstring tab_title;
  std::wstring final_url_title = UTF8ToWide("Title Of Awesomeness");
  // Wait till the final page has been loaded.
  for (int i = 0; i < 10; ++i) {
    PlatformThread::Sleep(sleep_timeout_ms());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title));
    if (tab_title == final_url_title) {
      ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
      break;
    }
  }

  // Check to make sure the navigation did in fact take place and we are
  // at the expected page.
  EXPECT_EQ(final_url_title, tab_title);

  bool final_navigation_not_redirect = true;
  // Check to make sure our request for files/title2.html doesn't get flagged
  // as a client redirect from the first (/client-redirect?) page.
  for (std::vector<GURL>::iterator it = redirects.begin();
       it != redirects.end(); ++it) {
    if (final_url.spec() == it->spec()) {
      final_navigation_not_redirect = false;
      break;
    }
  }
  EXPECT_TRUE(final_navigation_not_redirect);
}

}  // namespace
<commit_msg>Revert 59851 since we now avoid the problem with the testing webserver.<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.

// Navigates the browser to server and client redirect pages and makes sure
// that the correct redirects are reflected in the history database. Errors
// here might indicate that WebKit changed the calls our glue layer gets in
// the case of redirects. It may also mean problems with the history system.

#include "base/file_util.h"
#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/view_ids.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
#include "views/event.h"

namespace {

class RedirectTest : public UITest {
 public:
  RedirectTest()
      : test_server_(net::TestServer::TYPE_HTTP,
                     FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
  }

 protected:
  net::TestServer test_server_;
};

// Tests a single server redirect
TEST_F(RedirectTest, Server) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec());

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests a single client redirect.
TEST_F(RedirectTest, Client) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + final_url.spec());

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());

  // The address bar should display the final URL.
  GURL tab_url;
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);

  // Navigate one more time.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  // The address bar should still display the final URL.
  EXPECT_TRUE(tab_proxy->GetCurrentURL(&tab_url));
  EXPECT_TRUE(final_url == tab_url);
}

TEST_F(RedirectTest, ClientEmptyReferer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("file_client_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);

  // The client redirect appears as two page visits in the browser.
  NavigateToURLBlockUntilNavigationsComplete(first_url, 2);

  std::vector<GURL> redirects;
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  ASSERT_EQ(1U, redirects.size());
  EXPECT_EQ(final_url.spec(), redirects[0].spec());
}

// Tests to make sure a location change when a pending redirect exists isn't
// flagged as a redirect.
#if defined(OS_MACOSX)
// SimulateOSClick is broken on the Mac: http://crbug.com/45162
#define MAYBE_ClientCancelled DISABLED_ClientCancelled
#elif defined(OS_WIN)
// http://crbug.com/53091
#define MAYBE_ClientCancelled FAILS_ClientCancelled
#else
#define MAYBE_ClientCancelled ClientCancelled
#endif

TEST_F(RedirectTest, MAYBE_ClientCancelled) {
  FilePath first_path(test_data_directory_);
  first_path = first_path.AppendASCII("cancelled_redirect_test.html");
  ASSERT_TRUE(file_util::AbsolutePath(&first_path));
  GURL first_url = net::FilePathToFileURL(first_path);

  NavigateToURLBlockUntilNavigationsComplete(first_url, 1);

  scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
  ASSERT_TRUE(browser.get());
  scoped_refptr<WindowProxy> window = browser->GetWindow();
  ASSERT_TRUE(window.get());
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  int64 last_nav_time = 0;
  EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time));
  // Simulate a click to force to make a user-initiated location change;
  // otherwise, a non user-initiated in-page location change will be treated
  // as client redirect and the redirect will be recoreded, which can cause
  // this test failed.
  gfx::Rect tab_view_bounds;
  ASSERT_TRUE(browser->BringToFront());
  ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds,
                                    true));
  ASSERT_TRUE(
      window->SimulateOSClick(tab_view_bounds.CenterPoint(),
                              views::Event::EF_LEFT_BUTTON_DOWN));
  EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time));

  std::vector<GURL> redirects;
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));

  // There should be no redirects from first_url, because the anchor location
  // change that occurs should not be flagged as a redirect and the meta-refresh
  // won't have fired yet.
  ASSERT_EQ(0U, redirects.size());
  GURL current_url;
  ASSERT_TRUE(tab_proxy->GetCurrentURL(&current_url));

  // Need to test final path and ref separately since constructing a file url
  // containing an anchor using FilePathToFileURL will escape the anchor as
  // %23, but in current_url the anchor will be '#'.
  std::string final_ref = "myanchor";
  FilePath current_path;
  ASSERT_TRUE(net::FileURLToFilePath(current_url, &current_path));
  ASSERT_TRUE(file_util::AbsolutePath(&current_path));
  // Path should remain unchanged.
  EXPECT_EQ(StringToLowerASCII(first_path.value()),
            StringToLowerASCII(current_path.value()));
  EXPECT_EQ(final_ref, current_url.ref());
}

// Tests a client->server->server redirect
TEST_F(RedirectTest, ClientServerServer) {
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL(std::string());
  GURL next_to_last = test_server_.GetURL(
      "server-redirect?" + final_url.spec());
  GURL second_url = test_server_.GetURL(
      "server-redirect?" + next_to_last.spec());
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + second_url.spec());
  std::vector<GURL> redirects;

  // We need the sleep for the client redirects, because it appears as two
  // page visits in the browser.
  NavigateToURL(first_url);

  for (int i = 0; i < 10; ++i) {
    PlatformThread::Sleep(sleep_timeout_ms());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
    if (!redirects.empty())
      break;
  }

  ASSERT_EQ(3U, redirects.size());
  EXPECT_EQ(second_url.spec(), redirects[0].spec());
  EXPECT_EQ(next_to_last.spec(), redirects[1].spec());
  EXPECT_EQ(final_url.spec(), redirects[2].spec());
}

// Tests that the "#reference" gets preserved across server redirects.
TEST_F(RedirectTest, ServerReference) {
  ASSERT_TRUE(test_server_.Start());

  const std::string ref("reference");

  GURL final_url = test_server_.GetURL(std::string());
  GURL initial_url = test_server_.GetURL(
      "server-redirect?" + final_url.spec() + "#" + ref);

  NavigateToURL(initial_url);

  GURL url = GetActiveTabURL();
  EXPECT_EQ(ref, url.ref());
}

// Test that redirect from http:// to file:// :
// A) does not crash the browser or confuse the redirect chain, see bug 1080873
// B) does not take place.
TEST_F(RedirectTest, NoHttpToFile) {
  ASSERT_TRUE(test_server_.Start());
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("http_to_file.html");
  GURL file_url = net::FilePathToFileURL(test_file);

  GURL initial_url = test_server_.GetURL(
      "client-redirect?" + file_url.spec());

  NavigateToURL(initial_url);
  // UITest will check for crashes. We make sure the title doesn't match the
  // title from the file, because the nav should not have taken place.
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  std::wstring actual_title;
  ASSERT_TRUE(tab_proxy->GetTabTitle(&actual_title));
  EXPECT_NE("File!", WideToUTF8(actual_title));
}

// Ensures that non-user initiated location changes (within page) are
// flagged as client redirects. See bug 1139823.
TEST_F(RedirectTest, ClientFragments) {
  ASSERT_TRUE(test_server_.Start());

  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("ref_redirect.html");
  GURL first_url = net::FilePathToFileURL(test_file);
  std::vector<GURL> redirects;

  NavigateToURL(first_url);

  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
  EXPECT_EQ(1U, redirects.size());
  EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
}

// TODO(timsteele): This is disabled because our current testserver can't
// handle multiple requests in parallel, making it hang on the first request
// to /slow?60. It's unable to serve our second request for files/title2.html
// until /slow? completes, which doesn't give the desired behavior. We could
// alternatively load the second page from disk, but we would need to start
// the browser for this testcase with --process-per-tab, and I don't think
// we can do this at test-case-level granularity at the moment.
// http://crbug.com/45056
TEST_F(RedirectTest,
       DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
  // We want to initiate a second navigation after the provisional load for
  // the client redirect destination has started, but before this load is
  // committed. To achieve this, we tell the browser to load a slow page,
  // which causes it to start a provisional load, and while it is waiting
  // for the response (which means it hasn't committed the load for the client
  // redirect destination page yet), we issue a new navigation request.
  ASSERT_TRUE(test_server_.Start());

  GURL final_url = test_server_.GetURL("files/title2.html");
  GURL slow = test_server_.GetURL("slow?60");
  GURL first_url = test_server_.GetURL(
      "client-redirect?" + slow.spec());
  std::vector<GURL> redirects;

  NavigateToURL(first_url);
  // We don't sleep here - the first navigation won't have been committed yet
  // because we told the server to wait a minute. This means the browser has
  // started it's provisional load for the client redirect destination page but
  // hasn't completed. Our time is now!
  NavigateToURL(final_url);

  std::wstring tab_title;
  std::wstring final_url_title = UTF8ToWide("Title Of Awesomeness");
  // Wait till the final page has been loaded.
  for (int i = 0; i < 10; ++i) {
    PlatformThread::Sleep(sleep_timeout_ms());
    scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    ASSERT_TRUE(tab_proxy.get());
    ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title));
    if (tab_title == final_url_title) {
      ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
      break;
    }
  }

  // Check to make sure the navigation did in fact take place and we are
  // at the expected page.
  EXPECT_EQ(final_url_title, tab_title);

  bool final_navigation_not_redirect = true;
  // Check to make sure our request for files/title2.html doesn't get flagged
  // as a client redirect from the first (/client-redirect?) page.
  for (std::vector<GURL>::iterator it = redirects.begin();
       it != redirects.end(); ++it) {
    if (final_url.spec() == it->spec()) {
      final_navigation_not_redirect = false;
      break;
    }
  }
  EXPECT_TRUE(final_navigation_not_redirect);
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/ui/touch/tabs/touch_tab.h"

#include "base/logging.h"
#include "chrome/browser/themes/theme_service.h"
#include "grit/app_resources.h"
#include "grit/theme_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skbitmap_operations.h"

static const int kLeftPadding = 16;
static const int kRightPadding = 15;
static const int kDropShadowHeight = 2;

// The size of the favicon touch area. This generally would be the same as
// kFaviconSize in ui/gfx/favicon_size.h
static const int kTouchTabIconSize = 32;

TouchTab::TouchTabImage TouchTab::tab_alpha = {0};
TouchTab::TouchTabImage TouchTab::tab_active = {0};
TouchTab::TouchTabImage TouchTab::tab_inactive = {0};

////////////////////////////////////////////////////////////////////////////////
// TouchTab, public:

TouchTab::TouchTab(TabController* controller)
    : BaseTab(controller) {
  InitTabResources();
}

TouchTab::~TouchTab() {
}

// static
gfx::Size TouchTab::GetMinimumUnselectedSize() {
  InitTabResources();

  gfx::Size minimum_size;
  minimum_size.set_width(kLeftPadding + kRightPadding);
  minimum_size.set_height(32);
  return minimum_size;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, protected:
const gfx::Rect& TouchTab::GetTitleBounds() const {
  return title_bounds_;
}

const gfx::Rect& TouchTab::GetIconBounds() const {
  return favicon_bounds_;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, views::View overrides:

// We'll get selected via the mouse interactions with the TouchTabStrip.  There
// is no need to directly handle the mouse movements in the TouchTab.

bool TouchTab::OnMousePressed(const views::MouseEvent& event) {
  return false;
}

bool TouchTab::OnMouseDragged(const views::MouseEvent& event) {
  return false;
}

void TouchTab::OnMouseReleased(const views::MouseEvent& event) {
}

void TouchTab::OnPaint(gfx::Canvas* canvas) {
  // Don't paint if we're narrower than we can render correctly. (This should
  // only happen during animations).
  if (width() < GetMinimumUnselectedSize().width() && !data().mini)
    return;

  PaintTabBackground(canvas);

  SkColor title_color = GetThemeProvider()->
      GetColor(IsSelected() ?
          ThemeService::COLOR_TAB_TEXT :
          ThemeService::COLOR_BACKGROUND_TAB_TEXT);

  PaintTitle(canvas, title_color);
  PaintIcon(canvas);
}

void TouchTab::Layout() {
  gfx::Rect local_bounds = GetContentsBounds();
  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;
  int image_height = alpha->image_l->height();
  int x_base = tab_image->image_l->width();
  int y_base = height() - image_height;
  int center_width = width() - tab_image->l_width - tab_image->r_width;
  if (center_width < 0)
    center_width = 0;
  title_bounds_ = gfx::Rect(x_base, y_base, center_width, image_height);
  favicon_bounds_ = local_bounds;
}

bool TouchTab::HasHitTestMask() const {
  return true;
}

void TouchTab::GetHitTestMask(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);
  path->lineTo(0, 0);
  path->lineTo(w, 0);
  path->lineTo(w, h);
  path->lineTo(0, h);
  path->close();
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, private:

void TouchTab::PaintTabBackground(gfx::Canvas* canvas) {
  if (IsSelected()) {
    PaintActiveTabBackground(canvas);
  }
}

void TouchTab::PaintActiveTabBackground(gfx::Canvas* canvas) {
  int offset = GetMirroredX() + background_offset_.x();
  ThemeProvider* tp = GetThemeProvider();
  if (!tp)
    NOTREACHED() << "Unable to get theme provider";

  SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);

  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;

  // Draw left edge.
  int image_height = alpha->image_l->height();
  int y_base = height() - image_height;
  SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
      *tab_bg, offset, 0, tab_image->l_width, image_height);
  SkBitmap theme_l =
      SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
  canvas->DrawBitmapInt(theme_l, 0, y_base);

  // Draw right edge.
  SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg,
      offset + width() - tab_image->r_width, 0,
      tab_image->r_width, image_height);
  SkBitmap theme_r =
      SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
  canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, y_base);

  // Draw center.  Instead of masking out the top portion we simply skip over it
  // by incrementing by kDropShadowHeight, since it's a simple rectangle.
  canvas->TileImageInt(*tab_bg,
     offset + tab_image->l_width,
     kDropShadowHeight + tab_image->y_offset,
     tab_image->l_width,
     y_base + kDropShadowHeight + tab_image->y_offset,
     width() - tab_image->l_width - tab_image->r_width,
     height() - kDropShadowHeight - tab_image->y_offset);

  // Now draw the highlights/shadows around the tab edge.
  canvas->DrawBitmapInt(*tab_image->image_l, 0, y_base);
  canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, y_base,
      width() - tab_image->l_width - tab_image->r_width, image_height);
  canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width,
                        y_base);
}

void TouchTab::PaintIcon(gfx::Canvas* canvas) {
  // TODO(wyck): use thumbnailer to get better page images
  int x = favicon_bounds_.x();
  int y = favicon_bounds_.y();

  TouchTabImage* tab_image = &tab_active;
  int x_base = tab_image->image_l->width();

  x += x_base;

  if (base::i18n::IsRTL()) {
    x = width() - x -
        (data().favicon.isNull() ? kFaviconSize : data().favicon.width());
  }

  int favicon_x = x;
  if (!data().favicon.isNull() && data().favicon.width() != kFaviconSize)
    favicon_x += (data().favicon.width() - kFaviconSize) / 2;

  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
    ThemeProvider* tp = GetThemeProvider();
    SkBitmap frames(*tp->GetBitmapNamed(
        (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
        IDR_THROBBER_WAITING : IDR_THROBBER));
    int image_size = frames.height();
    int image_offset = loading_animation_frame() * image_size;
    canvas->DrawBitmapInt(frames, image_offset, 0, image_size, image_size, x, y,
                          kTouchTabIconSize, kTouchTabIconSize, false);
  } else {
    canvas->Save();
    canvas->ClipRectInt(0, 0, width(), height());
    if (should_display_crashed_favicon()) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
      canvas->DrawBitmapInt(crashed_favicon, 0, 0, crashed_favicon.width(),
          crashed_favicon.height(), x, y + favicon_hiding_offset(),
          kTouchTabIconSize, kTouchTabIconSize, true);
    } else {
      if (!data().favicon.isNull()) {

        if ((data().favicon.width() == kTouchTabIconSize) &&
            (data().favicon.height() == kTouchTabIconSize)) {
          canvas->DrawBitmapInt(data().favicon, 0, 0,
                                data().favicon.width(), data().favicon.height(),
                                x, y + favicon_hiding_offset(),
                                kTouchTabIconSize, kTouchTabIconSize, true);
        } else {
          // Draw a background around target touch area in case the favicon
          // is smaller than touch area (e.g www.google.com is 16x16 now)
          canvas->DrawRectInt(
              GetThemeProvider()->GetColor(
                  ThemeService::COLOR_BUTTON_BACKGROUND),
              x, y, kTouchTabIconSize, kTouchTabIconSize);

          // We center the image
          // TODO(saintlou): later request larger image from HistoryService
          canvas->DrawBitmapInt(data().favicon, 0, 0, data().favicon.width(),
              data().favicon.height(),
              x + ((kTouchTabIconSize - data().favicon.width()) / 2),
              y + ((kTouchTabIconSize - data().favicon.height()) / 2) +
                                                     favicon_hiding_offset(),
              data().favicon.width(), data().favicon.height(), true);
        }
      }
    }
    canvas->Restore();
  }
}

// static
void TouchTab::InitTabResources() {
  static bool initialized = false;
  if (initialized)
    return;

  initialized = true;

  // Load the tab images once now, and maybe again later if the theme changes.
  LoadTabImages();
}

// static
void TouchTab::LoadTabImages() {
  // We're not letting people override tab images just yet.
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();

  tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
  tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);

  tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
  tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
  tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
  tab_active.l_width = tab_active.image_l->width();
  tab_active.r_width = tab_active.image_r->width();

  tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
  tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
  tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
  tab_inactive.l_width = tab_inactive.image_l->width();
  tab_inactive.r_width = tab_inactive.image_r->width();
}
<commit_msg>Fix touch compile after r86955.<commit_after>// Copyright (c) 2011 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/ui/touch/tabs/touch_tab.h"

#include "base/logging.h"
#include "chrome/browser/themes/theme_service.h"
#include "grit/app_resources.h"
#include "grit/theme_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skbitmap_operations.h"

static const int kLeftPadding = 16;
static const int kRightPadding = 15;
static const int kDropShadowHeight = 2;

// The size of the favicon touch area. This generally would be the same as
// kFaviconSize in ui/gfx/favicon_size.h
static const int kTouchTabIconSize = 32;

TouchTab::TouchTabImage TouchTab::tab_alpha = {0};
TouchTab::TouchTabImage TouchTab::tab_active = {0};
TouchTab::TouchTabImage TouchTab::tab_inactive = {0};

////////////////////////////////////////////////////////////////////////////////
// TouchTab, public:

TouchTab::TouchTab(TabController* controller)
    : BaseTab(controller) {
  InitTabResources();
}

TouchTab::~TouchTab() {
}

// static
gfx::Size TouchTab::GetMinimumUnselectedSize() {
  InitTabResources();

  gfx::Size minimum_size;
  minimum_size.set_width(kLeftPadding + kRightPadding);
  minimum_size.set_height(32);
  return minimum_size;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, protected:
const gfx::Rect& TouchTab::GetTitleBounds() const {
  return title_bounds_;
}

const gfx::Rect& TouchTab::GetIconBounds() const {
  return favicon_bounds_;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, views::View overrides:

// We'll get selected via the mouse interactions with the TouchTabStrip.  There
// is no need to directly handle the mouse movements in the TouchTab.

bool TouchTab::OnMousePressed(const views::MouseEvent& event) {
  return false;
}

bool TouchTab::OnMouseDragged(const views::MouseEvent& event) {
  return false;
}

void TouchTab::OnMouseReleased(const views::MouseEvent& event) {
}

void TouchTab::OnPaint(gfx::Canvas* canvas) {
  // Don't paint if we're narrower than we can render correctly. (This should
  // only happen during animations).
  if (width() < GetMinimumUnselectedSize().width() && !data().mini)
    return;

  PaintTabBackground(canvas);

  SkColor title_color = GetThemeProvider()->
      GetColor(IsSelected() ?
          ThemeService::COLOR_TAB_TEXT :
          ThemeService::COLOR_BACKGROUND_TAB_TEXT);

  PaintTitle(canvas, title_color);
  PaintIcon(canvas);
}

void TouchTab::Layout() {
  gfx::Rect local_bounds = GetContentsBounds();
  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;
  int image_height = alpha->image_l->height();
  int x_base = tab_image->image_l->width();
  int y_base = height() - image_height;
  int center_width = width() - tab_image->l_width - tab_image->r_width;
  if (center_width < 0)
    center_width = 0;
  title_bounds_ = gfx::Rect(x_base, y_base, center_width, image_height);
  favicon_bounds_ = local_bounds;
}

bool TouchTab::HasHitTestMask() const {
  return true;
}

void TouchTab::GetHitTestMask(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);
  path->lineTo(0, 0);
  path->lineTo(w, 0);
  path->lineTo(w, h);
  path->lineTo(0, h);
  path->close();
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, private:

void TouchTab::PaintTabBackground(gfx::Canvas* canvas) {
  if (IsSelected()) {
    PaintActiveTabBackground(canvas);
  }
}

void TouchTab::PaintActiveTabBackground(gfx::Canvas* canvas) {
  int offset = GetMirroredX() + background_offset_.x();
  ui::ThemeProvider* tp = GetThemeProvider();
  if (!tp)
    NOTREACHED() << "Unable to get theme provider";

  SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);

  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;

  // Draw left edge.
  int image_height = alpha->image_l->height();
  int y_base = height() - image_height;
  SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
      *tab_bg, offset, 0, tab_image->l_width, image_height);
  SkBitmap theme_l =
      SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
  canvas->DrawBitmapInt(theme_l, 0, y_base);

  // Draw right edge.
  SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg,
      offset + width() - tab_image->r_width, 0,
      tab_image->r_width, image_height);
  SkBitmap theme_r =
      SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
  canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, y_base);

  // Draw center.  Instead of masking out the top portion we simply skip over it
  // by incrementing by kDropShadowHeight, since it's a simple rectangle.
  canvas->TileImageInt(*tab_bg,
     offset + tab_image->l_width,
     kDropShadowHeight + tab_image->y_offset,
     tab_image->l_width,
     y_base + kDropShadowHeight + tab_image->y_offset,
     width() - tab_image->l_width - tab_image->r_width,
     height() - kDropShadowHeight - tab_image->y_offset);

  // Now draw the highlights/shadows around the tab edge.
  canvas->DrawBitmapInt(*tab_image->image_l, 0, y_base);
  canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, y_base,
      width() - tab_image->l_width - tab_image->r_width, image_height);
  canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width,
                        y_base);
}

void TouchTab::PaintIcon(gfx::Canvas* canvas) {
  // TODO(wyck): use thumbnailer to get better page images
  int x = favicon_bounds_.x();
  int y = favicon_bounds_.y();

  TouchTabImage* tab_image = &tab_active;
  int x_base = tab_image->image_l->width();

  x += x_base;

  if (base::i18n::IsRTL()) {
    x = width() - x -
        (data().favicon.isNull() ? kFaviconSize : data().favicon.width());
  }

  int favicon_x = x;
  if (!data().favicon.isNull() && data().favicon.width() != kFaviconSize)
    favicon_x += (data().favicon.width() - kFaviconSize) / 2;

  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
    ui::ThemeProvider* tp = GetThemeProvider();
    SkBitmap frames(*tp->GetBitmapNamed(
        (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
        IDR_THROBBER_WAITING : IDR_THROBBER));
    int image_size = frames.height();
    int image_offset = loading_animation_frame() * image_size;
    canvas->DrawBitmapInt(frames, image_offset, 0, image_size, image_size, x, y,
                          kTouchTabIconSize, kTouchTabIconSize, false);
  } else {
    canvas->Save();
    canvas->ClipRectInt(0, 0, width(), height());
    if (should_display_crashed_favicon()) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
      canvas->DrawBitmapInt(crashed_favicon, 0, 0, crashed_favicon.width(),
          crashed_favicon.height(), x, y + favicon_hiding_offset(),
          kTouchTabIconSize, kTouchTabIconSize, true);
    } else {
      if (!data().favicon.isNull()) {

        if ((data().favicon.width() == kTouchTabIconSize) &&
            (data().favicon.height() == kTouchTabIconSize)) {
          canvas->DrawBitmapInt(data().favicon, 0, 0,
                                data().favicon.width(), data().favicon.height(),
                                x, y + favicon_hiding_offset(),
                                kTouchTabIconSize, kTouchTabIconSize, true);
        } else {
          // Draw a background around target touch area in case the favicon
          // is smaller than touch area (e.g www.google.com is 16x16 now)
          canvas->DrawRectInt(
              GetThemeProvider()->GetColor(
                  ThemeService::COLOR_BUTTON_BACKGROUND),
              x, y, kTouchTabIconSize, kTouchTabIconSize);

          // We center the image
          // TODO(saintlou): later request larger image from HistoryService
          canvas->DrawBitmapInt(data().favicon, 0, 0, data().favicon.width(),
              data().favicon.height(),
              x + ((kTouchTabIconSize - data().favicon.width()) / 2),
              y + ((kTouchTabIconSize - data().favicon.height()) / 2) +
                                                     favicon_hiding_offset(),
              data().favicon.width(), data().favicon.height(), true);
        }
      }
    }
    canvas->Restore();
  }
}

// static
void TouchTab::InitTabResources() {
  static bool initialized = false;
  if (initialized)
    return;

  initialized = true;

  // Load the tab images once now, and maybe again later if the theme changes.
  LoadTabImages();
}

// static
void TouchTab::LoadTabImages() {
  // We're not letting people override tab images just yet.
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();

  tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
  tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);

  tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
  tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
  tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
  tab_active.l_width = tab_active.image_l->width();
  tab_active.r_width = tab_active.image_r->width();

  tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
  tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
  tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
  tab_inactive.l_width = tab_inactive.image_l->width();
  tab_inactive.r_width = tab_inactive.image_r->width();
}
<|endoftext|>


<commit_before>// 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 "chrome/browser/ui/views/uninstall_view.h"

#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/run_loop.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/uninstall_browser_prompt.h"
#include "chrome/common/chrome_result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/shell_util.h"
#include "grit/chromium_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/label.h"
#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/widget/widget.h"

UninstallView::UninstallView(int* user_selection,
                             const base::Closure& quit_closure)
    : confirm_label_(NULL),
      delete_profile_(NULL),
      change_default_browser_(NULL),
      browsers_combo_(NULL),
      user_selection_(*user_selection),
      quit_closure_(quit_closure) {
  SetupControls();
}

UninstallView::~UninstallView() {
  // Exit the message loop we were started with so that uninstall can continue.
  quit_closure_.Run();
}

void UninstallView::SetupControls() {
  using views::ColumnSet;
  using views::GridLayout;

  GridLayout* layout = GridLayout::CreatePanel(this);
  SetLayoutManager(layout);

  // Message to confirm uninstallation.
  int column_set_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(column_set_id);
  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  layout->StartRow(0, column_set_id);
  confirm_label_ = new views::Label(
      l10n_util::GetStringUTF16(IDS_UNINSTALL_VERIFY));
  confirm_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  layout->AddView(confirm_label_);

  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);

  // The "delete profile" check box.
  ++column_set_id;
  column_set = layout->AddColumnSet(column_set_id);
  column_set->AddPaddingColumn(0, views::kPanelHorizIndentation);
  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  layout->StartRow(0, column_set_id);
  delete_profile_ = new views::Checkbox(
      l10n_util::GetStringUTF16(IDS_UNINSTALL_DELETE_PROFILE));
  layout->AddView(delete_profile_);

  // Set default browser combo box. If the default should not or cannot be
  // changed, widgets are not shown. We assume here that if Chrome cannot
  // be set programatically as default, neither can any other browser (for
  // instance because the OS doesn't permit that).
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  if (dist->CanSetAsDefault() &&
      ShellIntegration::IsDefaultBrowser() &&
      (ShellIntegration::CanSetAsDefaultBrowser() !=
          ShellIntegration::SET_DEFAULT_INTERACTIVE)) {
    browsers_.reset(new BrowsersMap());
    ShellUtil::GetRegisteredBrowsers(dist, browsers_.get());
    if (!browsers_->empty()) {
      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);

      ++column_set_id;
      column_set = layout->AddColumnSet(column_set_id);
      column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                            GridLayout::USE_PREF, 0, 0);
      column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                            GridLayout::USE_PREF, 0, 0);
      layout->StartRow(0, column_set_id);
      change_default_browser_ = new views::Checkbox(
          l10n_util::GetStringUTF16(IDS_UNINSTALL_SET_DEFAULT_BROWSER));
      change_default_browser_->set_listener(this);
      layout->AddView(change_default_browser_);
      browsers_combo_ = new views::Combobox(this);
      layout->AddView(browsers_combo_);
      browsers_combo_->SetEnabled(false);
    }
  }

  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
}

bool UninstallView::Accept() {
  user_selection_ = content::RESULT_CODE_NORMAL_EXIT;
  if (delete_profile_->checked())
    user_selection_ = chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE;
  if (change_default_browser_ && change_default_browser_->checked()) {
    BrowsersMap::const_iterator i = browsers_->begin();
    std::advance(i, browsers_combo_->selected_index());
    base::LaunchOptions options;
    options.start_hidden = true;
    base::LaunchProcess(i->second, options, NULL);
  }
  return true;
}

bool UninstallView::Cancel() {
  user_selection_ = chrome::RESULT_CODE_UNINSTALL_USER_CANCEL;
  return true;
}

string16 UninstallView::GetDialogButtonLabel(ui::DialogButton button) const {
  // We only want to give custom name to OK button - 'Uninstall'. Cancel
  // button remains same.
  if (button == ui::DIALOG_BUTTON_OK)
    return l10n_util::GetStringUTF16(IDS_UNINSTALL_BUTTON_TEXT);
  return string16();
}

void UninstallView::ButtonPressed(views::Button* sender,
                                  const ui::Event& event) {
  if (change_default_browser_ == sender) {
    // Disable the browsers combobox if the user unchecks the checkbox.
    DCHECK(browsers_combo_);
    browsers_combo_->SetEnabled(change_default_browser_->checked());
  }
}

string16 UninstallView::GetWindowTitle() const {
  return l10n_util::GetStringUTF16(IDS_UNINSTALL_CHROME);
}

views::View* UninstallView::GetContentsView() {
  return this;
}

int UninstallView::GetItemCount() const {
  DCHECK(!browsers_->empty());
  return browsers_->size();
}

string16 UninstallView::GetItemAt(int index) {
  DCHECK_LT(index, static_cast<int>(browsers_->size()));
  BrowsersMap::const_iterator i = browsers_->begin();
  std::advance(i, index);
  return i->first;
}

namespace chrome {

int ShowUninstallBrowserPrompt() {
  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
  int result = content::RESULT_CODE_NORMAL_EXIT;
  views::AcceleratorHandler accelerator_handler;
  base::RunLoop run_loop(&accelerator_handler);
  UninstallView* view = new UninstallView(&result, run_loop.QuitClosure());
  views::Widget::CreateWindow(view)->Show();
  run_loop.Run();
  return result;
}

}  // namespace chrome
<commit_msg>[win] fix checkbox padding in uninstall dialog<commit_after>// 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 "chrome/browser/ui/views/uninstall_view.h"

#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/run_loop.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/uninstall_browser_prompt.h"
#include "chrome/common/chrome_result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/shell_util.h"
#include "grit/chromium_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/label.h"
#include "ui/views/focus/accelerator_handler.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/widget/widget.h"

UninstallView::UninstallView(int* user_selection,
                             const base::Closure& quit_closure)
    : confirm_label_(NULL),
      delete_profile_(NULL),
      change_default_browser_(NULL),
      browsers_combo_(NULL),
      user_selection_(*user_selection),
      quit_closure_(quit_closure) {
  SetupControls();
}

UninstallView::~UninstallView() {
  // Exit the message loop we were started with so that uninstall can continue.
  quit_closure_.Run();
}

void UninstallView::SetupControls() {
  using views::ColumnSet;
  using views::GridLayout;

  GridLayout* layout = GridLayout::CreatePanel(this);
  SetLayoutManager(layout);

  // Message to confirm uninstallation.
  int column_set_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(column_set_id);
  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  layout->StartRow(0, column_set_id);
  confirm_label_ = new views::Label(
      l10n_util::GetStringUTF16(IDS_UNINSTALL_VERIFY));
  confirm_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  layout->AddView(confirm_label_);

  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);

  // The "delete profile" check box.
  ++column_set_id;
  column_set = layout->AddColumnSet(column_set_id);
  column_set->AddPaddingColumn(0, views::kPanelHorizIndentation);
  column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  layout->StartRow(0, column_set_id);
  delete_profile_ = new views::Checkbox(
      l10n_util::GetStringUTF16(IDS_UNINSTALL_DELETE_PROFILE));
  layout->AddView(delete_profile_);

  // Set default browser combo box. If the default should not or cannot be
  // changed, widgets are not shown. We assume here that if Chrome cannot
  // be set programatically as default, neither can any other browser (for
  // instance because the OS doesn't permit that).
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  if (dist->CanSetAsDefault() &&
      ShellIntegration::IsDefaultBrowser() &&
      (ShellIntegration::CanSetAsDefaultBrowser() !=
          ShellIntegration::SET_DEFAULT_INTERACTIVE)) {
    browsers_.reset(new BrowsersMap());
    ShellUtil::GetRegisteredBrowsers(dist, browsers_.get());
    if (!browsers_->empty()) {
      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);

      ++column_set_id;
      column_set = layout->AddColumnSet(column_set_id);
      column_set->AddPaddingColumn(0, views::kPanelHorizIndentation);
      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                            GridLayout::USE_PREF, 0, 0);
      column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
      column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                            GridLayout::USE_PREF, 0, 0);
      layout->StartRow(0, column_set_id);
      change_default_browser_ = new views::Checkbox(
          l10n_util::GetStringUTF16(IDS_UNINSTALL_SET_DEFAULT_BROWSER));
      change_default_browser_->set_listener(this);
      layout->AddView(change_default_browser_);
      browsers_combo_ = new views::Combobox(this);
      layout->AddView(browsers_combo_);
      browsers_combo_->SetEnabled(false);
    }
  }

  layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing);
}

bool UninstallView::Accept() {
  user_selection_ = content::RESULT_CODE_NORMAL_EXIT;
  if (delete_profile_->checked())
    user_selection_ = chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE;
  if (change_default_browser_ && change_default_browser_->checked()) {
    BrowsersMap::const_iterator i = browsers_->begin();
    std::advance(i, browsers_combo_->selected_index());
    base::LaunchOptions options;
    options.start_hidden = true;
    base::LaunchProcess(i->second, options, NULL);
  }
  return true;
}

bool UninstallView::Cancel() {
  user_selection_ = chrome::RESULT_CODE_UNINSTALL_USER_CANCEL;
  return true;
}

string16 UninstallView::GetDialogButtonLabel(ui::DialogButton button) const {
  // We only want to give custom name to OK button - 'Uninstall'. Cancel
  // button remains same.
  if (button == ui::DIALOG_BUTTON_OK)
    return l10n_util::GetStringUTF16(IDS_UNINSTALL_BUTTON_TEXT);
  return string16();
}

void UninstallView::ButtonPressed(views::Button* sender,
                                  const ui::Event& event) {
  if (change_default_browser_ == sender) {
    // Disable the browsers combobox if the user unchecks the checkbox.
    DCHECK(browsers_combo_);
    browsers_combo_->SetEnabled(change_default_browser_->checked());
  }
}

string16 UninstallView::GetWindowTitle() const {
  return l10n_util::GetStringUTF16(IDS_UNINSTALL_CHROME);
}

views::View* UninstallView::GetContentsView() {
  return this;
}

int UninstallView::GetItemCount() const {
  DCHECK(!browsers_->empty());
  return browsers_->size();
}

string16 UninstallView::GetItemAt(int index) {
  DCHECK_LT(index, static_cast<int>(browsers_->size()));
  BrowsersMap::const_iterator i = browsers_->begin();
  std::advance(i, index);
  return i->first;
}

namespace chrome {

int ShowUninstallBrowserPrompt() {
  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
  int result = content::RESULT_CODE_NORMAL_EXIT;
  views::AcceleratorHandler accelerator_handler;
  base::RunLoop run_loop(&accelerator_handler);
  UninstallView* view = new UninstallView(&result, run_loop.QuitClosure());
  views::Widget::CreateWindow(view)->Show();
  run_loop.Run();
  return result;
}

}  // namespace chrome
<|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/platform_thread.h"
#include "base/multiprocess_test.h"
#include "chrome/common/process_watcher.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class ProcessWatcherTest : public MultiProcessTest {
};

MULTIPROCESS_TEST_MAIN(Sleep1ChildProcess) {
  PlatformThread::Sleep(1000);
  exit(0);
  return 0;
}

MULTIPROCESS_TEST_MAIN(Sleep3ChildProcess) {
  PlatformThread::Sleep(3000);
  exit(0);
  return 0;
}

TEST_F(ProcessWatcherTest, DiesBeforeTermination) {
  base::ProcessHandle handle = this->SpawnChild(L"Sleep1ChildProcess");
  ASSERT_NE(static_cast<base::ProcessHandle>(NULL), handle);

  ProcessWatcher::EnsureProcessTerminated(handle);

  PlatformThread::Sleep(2500);
  // Normally we don't touch |handle| after calling EnsureProcessTerminated,
  // but we know the EnsureProcessTerminated process finishes in 2000 ms, so
  // it's safe to do so now. Same for Terminated test case below.
  EXPECT_FALSE(base::CrashAwareSleep(handle, 0));
}

TEST_F(ProcessWatcherTest, Terminated) {
  base::ProcessHandle handle = this->SpawnChild(L"Sleep3ChildProcess");
  ASSERT_NE(static_cast<base::ProcessHandle>(NULL), handle);

  ProcessWatcher::EnsureProcessTerminated(handle);

  PlatformThread::Sleep(2500);
  EXPECT_FALSE(base::CrashAwareSleep(handle, 0));
}

TEST_F(ProcessWatcherTest, NotTerminated) {
  base::ProcessHandle handle = this->SpawnChild(L"Sleep3ChildProcess");
  ASSERT_NE(static_cast<base::ProcessHandle>(NULL), handle);

  EXPECT_TRUE(base::CrashAwareSleep(handle, 2500));
  EXPECT_FALSE(base::CrashAwareSleep(handle, 1000));
}

}  // namespace
<commit_msg>Revert 21259 because it broke the unit tests on windows.<commit_after><|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "gc_clock.hh"
#include "timestamp.hh"
#include "schema.hh"
#include "atomic_cell.hh"
#include "tombstone.hh"
#include "exceptions/exceptions.hh"
#include "cql3/query_options.hh"

#include <unordered_map>

namespace cql3 {

/**
 * A simple container that simplify passing parameters for collections methods.
 */
class update_parameters final {
public:
    // Holder for data needed by CQL list updates which depend on current state of the list.
    struct prefetch_data {
        using key = std::pair<partition_key, clustering_key>;
        using key_view = std::pair<partition_key_view, clustering_key_view>;
        struct key_hashing {
            partition_key::hashing pk_hash;
            clustering_key::hashing ck_hash;

            key_hashing(const schema& s)
                : pk_hash(s)
                , ck_hash(s)
            { }

            size_t operator()(const key& k) const {
                return pk_hash(k.first) ^ ck_hash(k.second);
            }

            size_t operator()(const key_view& k) const {
                return pk_hash(k.first) ^ ck_hash(k.second);
            }
        };
        struct key_equality {
            partition_key::equality pk_eq;
            clustering_key::equality ck_eq;

            key_equality(const schema& s)
                : pk_eq(s)
                , ck_eq(s)
            { }

            bool operator()(const key& k1, const key& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
            bool operator()(const key_view& k1, const key& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
            bool operator()(const key& k1, const key_view& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
        };
        struct cell {
            bytes key;
            bytes value;
        };
        using cell_list = std::vector<cell>;
        using row = std::unordered_map<column_id, cell_list>;
    public:
        std::unordered_map<key, row, key_hashing, key_equality> rows;
        schema_ptr schema;
    public:
        prefetch_data(schema_ptr schema);
    };
    // Note: value (mutation) only required to contain the rows we are interested in
private:
    const gc_clock::duration _ttl;
    const prefetch_data _prefetched; // For operation that require a read-before-write
public:
    const api::timestamp_type _timestamp;
    const gc_clock::time_point _local_deletion_time;
    const schema_ptr _schema;
    const query_options& _options;

    update_parameters(const schema_ptr schema_, const query_options& options,
            api::timestamp_type timestamp, gc_clock::duration ttl, prefetch_data prefetched)
        : _ttl(ttl)
        , _prefetched(std::move(prefetched))
        , _timestamp(timestamp)
        , _local_deletion_time(gc_clock::now())
        , _schema(std::move(schema_))
        , _options(options)
    {
        // We use MIN_VALUE internally to mean the absence of of timestamp (in Selection, in sstable stats, ...), so exclude
        // it to avoid potential confusion.
        if (timestamp < api::min_timestamp || timestamp > api::max_timestamp) {
            throw exceptions::invalid_request_exception(format("Out of bound timestamp, must be in [{:d}, {:d}]",
                    api::min_timestamp, api::max_timestamp));
        }
    }

    atomic_cell make_dead_cell() const {
        return atomic_cell::make_dead(_timestamp, _local_deletion_time);
    }

    atomic_cell make_cell(const abstract_type& type, const fragmented_temporary_buffer::view& value, atomic_cell::collection_member cm = atomic_cell::collection_member::no) const {
        auto ttl = _ttl;

        if (ttl.count() <= 0) {
            ttl = _schema->default_time_to_live();
        }

        if (ttl.count() > 0) {
            return atomic_cell::make_live(type, _timestamp, value, _local_deletion_time + ttl, ttl, cm);
        } else {
            return atomic_cell::make_live(type, _timestamp, value, cm);
        }
    };

    atomic_cell make_cell(const abstract_type& type, bytes_view value, atomic_cell::collection_member cm = atomic_cell::collection_member::no) const {
        return make_cell(type, fragmented_temporary_buffer::view(value), cm);
    }

    atomic_cell make_counter_update_cell(int64_t delta) const {
        return atomic_cell::make_live_counter_update(_timestamp, delta);
    }

    tombstone make_tombstone() const {
        return {_timestamp, _local_deletion_time};
    }

    tombstone make_tombstone_just_before() const {
        return {_timestamp - 1, _local_deletion_time};
    }

#if 0
    public RangeTombstone makeRangeTombstone(ColumnSlice slice) throws InvalidRequestException
    {
        QueryProcessor.validateComposite(slice.start, metadata.comparator);
        QueryProcessor.validateComposite(slice.finish, metadata.comparator);
        return new RangeTombstone(slice.start, slice.finish, timestamp, localDeletionTime);
    }

    public RangeTombstone makeTombstoneForOverwrite(ColumnSlice slice) throws InvalidRequestException
    {
        QueryProcessor.validateComposite(slice.start, metadata.comparator);
        QueryProcessor.validateComposite(slice.finish, metadata.comparator);
        return new RangeTombstone(slice.start, slice.finish, timestamp - 1, localDeletionTime);
    }
#endif

    gc_clock::duration ttl() const {
        return _ttl.count() > 0 ? _ttl : _schema->default_time_to_live();
    }

    gc_clock::time_point expiry() const {
        return ttl() + _local_deletion_time;
    }

    api::timestamp_type timestamp() const {
        return _timestamp;
    }

    const prefetch_data::cell_list*
    get_prefetched_list(
        partition_key_view pkey,
        clustering_key_view ckey,
        const column_definition& column) const;

    static prefetch_data build_prefetch_data(schema_ptr schema, const query::result& query_result,
            const query::partition_slice& slice);
};

}
<commit_msg>lwt: remove dead code in cql3/update_parameters.hh<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "gc_clock.hh"
#include "timestamp.hh"
#include "schema.hh"
#include "atomic_cell.hh"
#include "tombstone.hh"
#include "exceptions/exceptions.hh"
#include "cql3/query_options.hh"

#include <unordered_map>

namespace cql3 {

/**
 * A simple container that simplify passing parameters for collections methods.
 */
class update_parameters final {
public:
    // Holder for data needed by CQL list updates which depend on current state of the list.
    struct prefetch_data {
        using key = std::pair<partition_key, clustering_key>;
        using key_view = std::pair<partition_key_view, clustering_key_view>;
        struct key_hashing {
            partition_key::hashing pk_hash;
            clustering_key::hashing ck_hash;

            key_hashing(const schema& s)
                : pk_hash(s)
                , ck_hash(s)
            { }

            size_t operator()(const key& k) const {
                return pk_hash(k.first) ^ ck_hash(k.second);
            }

            size_t operator()(const key_view& k) const {
                return pk_hash(k.first) ^ ck_hash(k.second);
            }
        };
        struct key_equality {
            partition_key::equality pk_eq;
            clustering_key::equality ck_eq;

            key_equality(const schema& s)
                : pk_eq(s)
                , ck_eq(s)
            { }

            bool operator()(const key& k1, const key& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
            bool operator()(const key_view& k1, const key& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
            bool operator()(const key& k1, const key_view& k2) const {
                return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
            }
        };
        struct cell {
            bytes key;
            bytes value;
        };
        using cell_list = std::vector<cell>;
        using row = std::unordered_map<column_id, cell_list>;
    public:
        std::unordered_map<key, row, key_hashing, key_equality> rows;
        schema_ptr schema;
    public:
        prefetch_data(schema_ptr schema);
    };
    // Note: value (mutation) only required to contain the rows we are interested in
private:
    const gc_clock::duration _ttl;
    const prefetch_data _prefetched; // For operation that require a read-before-write
public:
    const api::timestamp_type _timestamp;
    const gc_clock::time_point _local_deletion_time;
    const schema_ptr _schema;
    const query_options& _options;

    update_parameters(const schema_ptr schema_, const query_options& options,
            api::timestamp_type timestamp, gc_clock::duration ttl, prefetch_data prefetched)
        : _ttl(ttl)
        , _prefetched(std::move(prefetched))
        , _timestamp(timestamp)
        , _local_deletion_time(gc_clock::now())
        , _schema(std::move(schema_))
        , _options(options)
    {
        // We use MIN_VALUE internally to mean the absence of of timestamp (in Selection, in sstable stats, ...), so exclude
        // it to avoid potential confusion.
        if (timestamp < api::min_timestamp || timestamp > api::max_timestamp) {
            throw exceptions::invalid_request_exception(format("Out of bound timestamp, must be in [{:d}, {:d}]",
                    api::min_timestamp, api::max_timestamp));
        }
    }

    atomic_cell make_dead_cell() const {
        return atomic_cell::make_dead(_timestamp, _local_deletion_time);
    }

    atomic_cell make_cell(const abstract_type& type, const fragmented_temporary_buffer::view& value, atomic_cell::collection_member cm = atomic_cell::collection_member::no) const {
        auto ttl = _ttl;

        if (ttl.count() <= 0) {
            ttl = _schema->default_time_to_live();
        }

        if (ttl.count() > 0) {
            return atomic_cell::make_live(type, _timestamp, value, _local_deletion_time + ttl, ttl, cm);
        } else {
            return atomic_cell::make_live(type, _timestamp, value, cm);
        }
    };

    atomic_cell make_cell(const abstract_type& type, bytes_view value, atomic_cell::collection_member cm = atomic_cell::collection_member::no) const {
        return make_cell(type, fragmented_temporary_buffer::view(value), cm);
    }

    atomic_cell make_counter_update_cell(int64_t delta) const {
        return atomic_cell::make_live_counter_update(_timestamp, delta);
    }

    tombstone make_tombstone() const {
        return {_timestamp, _local_deletion_time};
    }

    tombstone make_tombstone_just_before() const {
        return {_timestamp - 1, _local_deletion_time};
    }

    gc_clock::duration ttl() const {
        return _ttl.count() > 0 ? _ttl : _schema->default_time_to_live();
    }

    gc_clock::time_point expiry() const {
        return ttl() + _local_deletion_time;
    }

    api::timestamp_type timestamp() const {
        return _timestamp;
    }

    const prefetch_data::cell_list*
    get_prefetched_list(
        partition_key_view pkey,
        clustering_key_view ckey,
        const column_definition& column) const;

    static prefetch_data build_prefetch_data(schema_ptr schema, const query::result& query_result,
            const query::partition_slice& slice);
};

}
<|endoftext|>