<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed 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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef itkRelabelComponentImageFilter_hxx
#define itkRelabelComponentImageFilter_hxx

#include "itkRelabelComponentImageFilter.h"
#include "itkImageRegionIterator.h"
#include "itkNumericTraits.h"
#include "itkProgressReporter.h"
#include "itkProgressTransformer.h"
#include "itkImageScanlineIterator.h"
#include <map>
#include <utility>

namespace itk
{
template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateInputRequestedRegion()
{
  // call the superclass' implementation of this method
  Superclass::GenerateInputRequestedRegion();

  // We need all the input.
  InputImagePointer input = const_cast<InputImageType *>(this->GetInput());
  if (input)
  {
    input->SetRequestedRegion(input->GetLargestPossibleRegion());
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::ParallelComputeLabels(const RegionType & inputRegionForThread)
{
  RelabelComponentObjectType initialSize;
  initialSize.m_SizeInPixels = 0;

  // walk the input
  ImageScanlineConstIterator<InputImageType> it(this->GetInput(), inputRegionForThread);

  MapType localSizeMap;

  auto mapIt = localSizeMap.end();
  while (!it.IsAtEnd())
  {
    while (!it.IsAtEndOfLine())
    {
      // Get the input pixel value
      const auto inputValue = it.Get();

      // if the input pixel is not the background
      if (inputValue != NumericTraits<LabelType>::ZeroValue())
      {
        // label is not currently in the map
        mapIt = localSizeMap.insert(mapIt, { inputValue, initialSize });

        // label is already in the map, update the values
        ++(mapIt->second.m_SizeInPixels);
      }

      // increment the iterator
      ++it;
    }
    it.NextLine();
  }

  // Merge localStatistics and m_LabelStatistics concurrently safe in a
  // local copy, this thread may do multiple merges.
  while (true)
  {
    std::unique_lock<std::mutex> lock(m_Mutex);

    if (m_SizeMap.empty())
    {
      swap(m_SizeMap, localSizeMap);
      break;
    }
    else
    {
      // copy the output map to thread local storage
      MapType toMerge;
      swap(m_SizeMap, toMerge);

      // allow other threads to merge data
      lock.unlock();

      // Merge toMerge into localSizeMap, locally
      for (auto & sizePair : toMerge)
      {
        localSizeMap[sizePair.first] += sizePair.second;
      }
    }
  } // release lock
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateData()
{
  using LabelComponentPairType = std::pair<LabelType, RelabelComponentObjectType>;

  // Get the input and the output
  const TInputImage * input = this->GetInput();
  TOutputImage *      output = this->GetOutput();

  // Calculate the size of pixel
  float physicalPixelSize = 1.0;
  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
  {
    physicalPixelSize *= input->GetSpacing()[i];
  }

  // Walk the entire input image and compute used labels and the number of each label.
  ProgressTransformer progressTransformer1(0.0f, 0.5f, this);
  this->GetMultiThreader()->template ParallelizeImageRegion<ImageDimension>(
    input->GetRequestedRegion(),
    [this](const RegionType & inputRegion) { this->ParallelComputeLabels(inputRegion); },
    progressTransformer1.GetProcessObject());

  // Construct an array of the label, component information pair to sort
  auto sizeVector = std::vector<LabelComponentPairType>(m_SizeMap.begin(), m_SizeMap.end());

  // free memory by swapping to a default constructed object.
  MapType().swap(m_SizeMap);

  // Sort the objects by size by default, unless m_SortByObjectSize
  // is set to false.
  if (m_SortByObjectSize)
  {
    std::sort(sizeVector.begin(),
              sizeVector.end(),
              [](const LabelComponentPairType & a, const LabelComponentPairType & b) -> bool {
                return a.second.m_SizeInPixels > b.second.m_SizeInPixels ||
                       (!(a.second.m_SizeInPixels < b.second.m_SizeInPixels) && a.first < b.first);
              });
  }

  // A map from the input pixel labels to the output labels
  using RelabelMapType = std::map<LabelType, OutputPixelType>;
  RelabelMapType relabelMap;

  // create a lookup table to map the input label to the output label.
  // cache the object sizes for later access by the user
  m_NumberOfObjects = sizeVector.size();
  m_OriginalNumberOfObjects = sizeVector.size();
  m_SizeOfObjectsInPixels.clear();
  m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  SizeValueType   NumberOfObjectsRemoved = 0;
  OutputPixelType outputLabel = 0;
  for (const auto & sizeVectorPair : sizeVector)
  {
    // skip objects that are too small ( but don't increment the output label )
    if (m_MinimumObjectSize > 0 && sizeVectorPair.second.m_SizeInPixels < m_MinimumObjectSize)
    {
      // map small objects to the background
      ++NumberOfObjectsRemoved;
      relabelMap.insert({ sizeVectorPair.first, NumericTraits<OutputPixelType>::ZeroValue() });
    }
    else
    {
      if (outputLabel == NumericTraits<OutputPixelType>::max())
      {
        itkExceptionMacro("Output range exceeded!");
      }
      // map for input labels to output labels (Note we use i+1 in the
      // map since index 0 is the background)
      relabelMap.insert({ sizeVectorPair.first, outputLabel + 1 });

      // cache object sizes for later access by the user
      m_SizeOfObjectsInPixels[outputLabel] = sizeVectorPair.second.m_SizeInPixels;
      ++outputLabel;
    }
  }

  // update number of objects and resize vectors if we have removed small
  // objects
  m_NumberOfObjects -= NumberOfObjectsRemoved;
  if (NumberOfObjectsRemoved > 0)
  {
    m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  }

  // compute the object sizes in physical space too
  m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  std::transform(m_SizeOfObjectsInPixels.begin(),
                 m_SizeOfObjectsInPixels.end(),
                 m_SizeOfObjectsInPhysicalUnits.begin(),
                 [physicalPixelSize](ObjectSizeType sizeInPixels) { return sizeInPixels * physicalPixelSize; });

  // After the objects stats are computed add in the background label so the relabelMap can be directly applied.
  relabelMap.insert({ NumericTraits<LabelType>::ZeroValue(), NumericTraits<OutputPixelType>::ZeroValue() });

  // Second pass: walk just the output requested region and relabel
  // the necessary pixels.
  //

  // Allocate the output
  this->AllocateOutputs();

  // In parallel apply the relabling map
  ProgressTransformer progressTransformer2(0.5f, 1.0f, this);
  this->GetMultiThreader()->template ParallelizeImageRegion<ImageDimension>(
    output->GetRequestedRegion(),
    [this, &relabelMap](const RegionType & outputRegionForThread) {
      ImageScanlineIterator<OutputImageType>     oit(this->GetOutput(), outputRegionForThread);
      ImageScanlineConstIterator<InputImageType> it(this->GetInput(), outputRegionForThread);

      auto mapIt = relabelMap.cbegin();

      while (!oit.IsAtEnd())
      {
        while (!oit.IsAtEndOfLine())
        {
          const auto && inputValue = it.Get();

          if (mapIt->first != inputValue)
          {
            mapIt = relabelMap.find(inputValue);
          }

          // no new labels should be encountered in the input
          assert(mapIt != mapIt.cend());

          oit.Set(mapIt->second);

          ++oit;
          ++it;
        }
        oit.NextLine();
        it.NextLine();
      }
    },
    progressTransformer2.GetProcessObject());
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "NumberOfObjects: " << m_NumberOfObjects << std::endl;
  os << indent << "OriginalNumberOfObjects: " << m_OriginalNumberOfObjects << std::endl;
  os << indent << "NumberOfObjectsToPrint: " << m_NumberOfObjectsToPrint << std::endl;
  os << indent << "MinimumObjectSizes: " << m_MinimumObjectSize << std::endl;
  os << indent << "SortByObjectSize: " << m_SortByObjectSize << std::endl;

  typename ObjectSizeInPixelsContainerType::const_iterator it;
  ObjectSizeInPhysicalUnitsContainerType::const_iterator   fit;
  SizeValueType                                            i;

  // limit the number of objects to print
  SizeValueType numPrint = std::min(m_NumberOfObjectsToPrint, m_SizeOfObjectsInPixels.size());

  for (i = 0, it = m_SizeOfObjectsInPixels.begin(), fit = m_SizeOfObjectsInPhysicalUnits.begin(); i < numPrint;
       ++it, ++fit, ++i)
  {
    os << indent << "Object #" << i + 1 << ": " << *it << " pixels, " << *fit << " physical units" << std::endl;
  }
  if (numPrint < m_SizeOfObjectsInPixels.size())
  {
    os << indent << "..." << std::endl;
  }
}
} // end namespace itk

#endif
<commit_msg>COMP: Fixes error "error: no member named 'cend' in 'std::__1::__map_const..."<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed 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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef itkRelabelComponentImageFilter_hxx
#define itkRelabelComponentImageFilter_hxx

#include "itkRelabelComponentImageFilter.h"
#include "itkImageRegionIterator.h"
#include "itkNumericTraits.h"
#include "itkProgressReporter.h"
#include "itkProgressTransformer.h"
#include "itkImageScanlineIterator.h"
#include <map>
#include <utility>

namespace itk
{
template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateInputRequestedRegion()
{
  // call the superclass' implementation of this method
  Superclass::GenerateInputRequestedRegion();

  // We need all the input.
  InputImagePointer input = const_cast<InputImageType *>(this->GetInput());
  if (input)
  {
    input->SetRequestedRegion(input->GetLargestPossibleRegion());
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::ParallelComputeLabels(const RegionType & inputRegionForThread)
{
  RelabelComponentObjectType initialSize;
  initialSize.m_SizeInPixels = 0;

  // walk the input
  ImageScanlineConstIterator<InputImageType> it(this->GetInput(), inputRegionForThread);

  MapType localSizeMap;

  auto mapIt = localSizeMap.end();
  while (!it.IsAtEnd())
  {
    while (!it.IsAtEndOfLine())
    {
      // Get the input pixel value
      const auto inputValue = it.Get();

      // if the input pixel is not the background
      if (inputValue != NumericTraits<LabelType>::ZeroValue())
      {
        // label is not currently in the map
        mapIt = localSizeMap.insert(mapIt, { inputValue, initialSize });

        // label is already in the map, update the values
        ++(mapIt->second.m_SizeInPixels);
      }

      // increment the iterator
      ++it;
    }
    it.NextLine();
  }

  // Merge localStatistics and m_LabelStatistics concurrently safe in a
  // local copy, this thread may do multiple merges.
  while (true)
  {
    std::unique_lock<std::mutex> lock(m_Mutex);

    if (m_SizeMap.empty())
    {
      swap(m_SizeMap, localSizeMap);
      break;
    }
    else
    {
      // copy the output map to thread local storage
      MapType toMerge;
      swap(m_SizeMap, toMerge);

      // allow other threads to merge data
      lock.unlock();

      // Merge toMerge into localSizeMap, locally
      for (auto & sizePair : toMerge)
      {
        localSizeMap[sizePair.first] += sizePair.second;
      }
    }
  } // release lock
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateData()
{
  using LabelComponentPairType = std::pair<LabelType, RelabelComponentObjectType>;

  // Get the input and the output
  const TInputImage * input = this->GetInput();
  TOutputImage *      output = this->GetOutput();

  // Calculate the size of pixel
  float physicalPixelSize = 1.0;
  for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i)
  {
    physicalPixelSize *= input->GetSpacing()[i];
  }

  // Walk the entire input image and compute used labels and the number of each label.
  ProgressTransformer progressTransformer1(0.0f, 0.5f, this);
  this->GetMultiThreader()->template ParallelizeImageRegion<ImageDimension>(
    input->GetRequestedRegion(),
    [this](const RegionType & inputRegion) { this->ParallelComputeLabels(inputRegion); },
    progressTransformer1.GetProcessObject());

  // Construct an array of the label, component information pair to sort
  auto sizeVector = std::vector<LabelComponentPairType>(m_SizeMap.begin(), m_SizeMap.end());

  // free memory by swapping to a default constructed object.
  MapType().swap(m_SizeMap);

  // Sort the objects by size by default, unless m_SortByObjectSize
  // is set to false.
  if (m_SortByObjectSize)
  {
    std::sort(sizeVector.begin(),
              sizeVector.end(),
              [](const LabelComponentPairType & a, const LabelComponentPairType & b) -> bool {
                return a.second.m_SizeInPixels > b.second.m_SizeInPixels ||
                       (!(a.second.m_SizeInPixels < b.second.m_SizeInPixels) && a.first < b.first);
              });
  }

  // A map from the input pixel labels to the output labels
  using RelabelMapType = std::map<LabelType, OutputPixelType>;
  RelabelMapType relabelMap;

  // create a lookup table to map the input label to the output label.
  // cache the object sizes for later access by the user
  m_NumberOfObjects = sizeVector.size();
  m_OriginalNumberOfObjects = sizeVector.size();
  m_SizeOfObjectsInPixels.clear();
  m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  SizeValueType   NumberOfObjectsRemoved = 0;
  OutputPixelType outputLabel = 0;
  for (const auto & sizeVectorPair : sizeVector)
  {
    // skip objects that are too small ( but don't increment the output label )
    if (m_MinimumObjectSize > 0 && sizeVectorPair.second.m_SizeInPixels < m_MinimumObjectSize)
    {
      // map small objects to the background
      ++NumberOfObjectsRemoved;
      relabelMap.insert({ sizeVectorPair.first, NumericTraits<OutputPixelType>::ZeroValue() });
    }
    else
    {
      if (outputLabel == NumericTraits<OutputPixelType>::max())
      {
        itkExceptionMacro("Output range exceeded!");
      }
      // map for input labels to output labels (Note we use i+1 in the
      // map since index 0 is the background)
      relabelMap.insert({ sizeVectorPair.first, outputLabel + 1 });

      // cache object sizes for later access by the user
      m_SizeOfObjectsInPixels[outputLabel] = sizeVectorPair.second.m_SizeInPixels;
      ++outputLabel;
    }
  }

  // update number of objects and resize vectors if we have removed small
  // objects
  m_NumberOfObjects -= NumberOfObjectsRemoved;
  if (NumberOfObjectsRemoved > 0)
  {
    m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  }

  // compute the object sizes in physical space too
  m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  std::transform(m_SizeOfObjectsInPixels.begin(),
                 m_SizeOfObjectsInPixels.end(),
                 m_SizeOfObjectsInPhysicalUnits.begin(),
                 [physicalPixelSize](ObjectSizeType sizeInPixels) { return sizeInPixels * physicalPixelSize; });

  // After the objects stats are computed add in the background label so the relabelMap can be directly applied.
  relabelMap.insert({ NumericTraits<LabelType>::ZeroValue(), NumericTraits<OutputPixelType>::ZeroValue() });

  // Second pass: walk just the output requested region and relabel
  // the necessary pixels.
  //

  // Allocate the output
  this->AllocateOutputs();

  // In parallel apply the relabling map
  ProgressTransformer progressTransformer2(0.5f, 1.0f, this);
  this->GetMultiThreader()->template ParallelizeImageRegion<ImageDimension>(
    output->GetRequestedRegion(),
    [this, &relabelMap](const RegionType & outputRegionForThread) {
      ImageScanlineIterator<OutputImageType>     oit(this->GetOutput(), outputRegionForThread);
      ImageScanlineConstIterator<InputImageType> it(this->GetInput(), outputRegionForThread);

      auto mapIt = relabelMap.cbegin();

      while (!oit.IsAtEnd())
      {
        while (!oit.IsAtEndOfLine())
        {
          const auto && inputValue = it.Get();

          if (mapIt->first != inputValue)
          {
            mapIt = relabelMap.find(inputValue);
          }

          // no new labels should be encountered in the input
          assert(mapIt != relabelMap.cend());

          oit.Set(mapIt->second);

          ++oit;
          ++it;
        }
        oit.NextLine();
        it.NextLine();
      }
    },
    progressTransformer2.GetProcessObject());
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "NumberOfObjects: " << m_NumberOfObjects << std::endl;
  os << indent << "OriginalNumberOfObjects: " << m_OriginalNumberOfObjects << std::endl;
  os << indent << "NumberOfObjectsToPrint: " << m_NumberOfObjectsToPrint << std::endl;
  os << indent << "MinimumObjectSizes: " << m_MinimumObjectSize << std::endl;
  os << indent << "SortByObjectSize: " << m_SortByObjectSize << std::endl;

  typename ObjectSizeInPixelsContainerType::const_iterator it;
  ObjectSizeInPhysicalUnitsContainerType::const_iterator   fit;
  SizeValueType                                            i;

  // limit the number of objects to print
  SizeValueType numPrint = std::min(m_NumberOfObjectsToPrint, m_SizeOfObjectsInPixels.size());

  for (i = 0, it = m_SizeOfObjectsInPixels.begin(), fit = m_SizeOfObjectsInPhysicalUnits.begin(); i < numPrint;
       ++it, ++fit, ++i)
  {
    os << indent << "Object #" << i + 1 << ": " << *it << " pixels, " << *fit << " physical units" << std::endl;
  }
  if (numPrint < m_SizeOfObjectsInPixels.size())
  {
    os << indent << "..." << std::endl;
  }
}
} // end namespace itk

#endif
<|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/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  void RunIncognitoTest(const std::wstring& test_case) {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    // Open an Incognito window.
    int window_count;
    ASSERT_TRUE(browser->RunCommand(IDC_NEW_INCOGNITO_WINDOW));
    scoped_refptr<BrowserProxy> incognito(automation()->GetBrowserWindow(1));
    scoped_refptr<TabProxy> tab(incognito->GetTab(0));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(2, window_count);

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);

    // Close the incognito window
    ASSERT_TRUE(incognito->RunCommand(IDC_CLOSE_WINDOW));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);

    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  bool WaitForProcessCountToBe(int tabs, int workers) {
    // The 1 is for the browser process.
    int number_of_processes = 1 + workers +
        (UITest::in_process_renderer() ? 0 : tabs);
#if defined(OS_LINUX)
    // On Linux, we also have a zygote process and a sandbox host process.
    number_of_processes += 2;
#endif

    int cur_process_count;
    for (int i = 0; i < 10; ++i) {
      cur_process_count = GetBrowserProcessCount();
      if (cur_process_count == number_of_processes)
        return true;

      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }

    EXPECT_EQ(number_of_processes, cur_process_count);
    return false;
  }
};

#if defined(OS_LINUX)
// Fails running under valgrind, http://crbug.com/28445
#define SingleWorker DISABLED_SingleWorker
#endif

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

// Incognito windows should not share workers with non-incognito windows
TEST_F(WorkerTest, IncognitoSharedWorkers) {
  // Load a non-incognito tab and have it create a shared worker
  RunTest(L"incognito_worker.html");
  // Incognito worker should not share with non-incognito
  RunIncognitoTest(L"incognito_worker.html");
}

#if defined(OS_LINUX) || defined (OS_MACOSX)
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#endif

TEST_F(WorkerTest, WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
    "use-machine-stack.html",
    "worker-call.html",
    "worker-cloneport.html",
    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);

  // Navigate away from to a blank page so that any workers are cleaned up. This
  // helps leaks trackers do a better job of reporting.
  scoped_refptr<TabProxy> tab(GetActiveTab());
  GURL about_url(std::string("file://localhost/"));
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(about_url));
}

#if defined(OS_WIN) || defined(OS_MACOSX)
// http://crbug.com/27636 - incorrect URL_MISMATCH exceptions sometimes get
// generated on the windows try bots.
// http://crbug.com/28445 - flakiness on mac
#define SharedWorkerFastLayoutTests DISABLED_SharedWorkerFastLayoutTests
#endif

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// These tests are flaky on linux/views builds.
// See http://crbug.com/28808.
#define MessagePorts FLAKY_MessagePorts
#define SharedWorkerFastLayoutTests FLAKY_SharedWorkerFastLayoutTests
#endif

TEST_F(WorkerTest, SharedWorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-constructor.html",
    "shared-worker-context-gc.html",
    "shared-worker-event-listener.html",
    "shared-worker-exception.html",
    "shared-worker-gc.html",
    // Lifecycle tests rely on layoutTestController.workerThreadCount which is
    // not currently implemented.
    //"shared-worker-frame-lifecycle.html",
    //"shared-worker-lifecycle.html",
    "shared-worker-load-error.html",
    "shared-worker-location.html",
    "shared-worker-name.html",
    "shared-worker-navigator.html",
    "shared-worker-replace-global-constructor.html",
    "shared-worker-replace-self.html",
    "shared-worker-script-error.html",
    "shared-worker-shared.html",
    "shared-worker-simple.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i) {
    RunLayoutTest(kLayoutTestFiles[i], false);
    // Shared workers will error out if we ever have more than one tab open.
    int window_count = 0;
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);
    EXPECT_EQ(1, GetTabCount());
  }
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-importScripts.html",
    "shared-worker-redirect.html",
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

#if defined(OS_LINUX)
// Fails running under valgrind http://crbug.com/28445
#define WorkerXhrHttpLayoutTests DISABLED_WorkerXhrHttpLayoutTests
#endif

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    // These tests (and the shared-worker versions below) are disabled due to
    // limitations in lighttpd (doesn't handle all of the HTTP methods).
    //"methods-async.html",
    //"methods.html",

    "shared-worker-close.html",
    // Disabled due to limitations in lighttpd (does not handle methods other
    // than GET/PUT/POST).
    //"shared-worker-methods-async.html",
    //"shared-worker-methods.html",
    "shared-worker-xhr-file-not-found.html",

    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

// Disable LimitPerPage on Linux. Seems to work on Mac though:
// http://code.google.com/p/chromium/issues/detail?id=22608
#if !defined(OS_LINUX)
// This test fails after WebKit merge 49414:49432. (BUG=24652)
TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  ASSERT_TRUE(WaitForProcessCountToBe(1, max_workers_per_tab));
}
#endif

#if defined(OS_LINUX)
// Fails (crashes) on Linux Tests: http://crbug.com/28445
#define LimitTotal DISABLED_LimitTotal
#elif defined(OS_MACOSX)
// Doesn't crash, but on Mac it sometimes fails for a few runs in a row,
// http://crbug.com/28445
#define LimitTotal FLAKY_LimitTotal
#endif

TEST_F(WorkerTest, LimitTotal) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));

  // Now close a page and check that the queued workers were started.
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));
}
<commit_msg>Marking failing IncognitoSharedWorkers uitest as flaky on Linux.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"

static const char kTestCompleteCookie[] = "status";
static const char kTestCompleteSuccess[] = "OK";

class WorkerTest : public UILayoutTest {
 protected:
  virtual ~WorkerTest() { }

  void RunTest(const std::wstring& test_case) {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  void RunIncognitoTest(const std::wstring& test_case) {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    // Open an Incognito window.
    int window_count;
    ASSERT_TRUE(browser->RunCommand(IDC_NEW_INCOGNITO_WINDOW));
    scoped_refptr<BrowserProxy> incognito(automation()->GetBrowserWindow(1));
    scoped_refptr<TabProxy> tab(incognito->GetTab(0));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(2, window_count);

    GURL url = GetTestUrl(L"workers", test_case);
    ASSERT_TRUE(tab->NavigateToURL(url));

    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);

    // Close the incognito window
    ASSERT_TRUE(incognito->RunCommand(IDC_CLOSE_WINDOW));
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);

    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
  }

  bool WaitForProcessCountToBe(int tabs, int workers) {
    // The 1 is for the browser process.
    int number_of_processes = 1 + workers +
        (UITest::in_process_renderer() ? 0 : tabs);
#if defined(OS_LINUX)
    // On Linux, we also have a zygote process and a sandbox host process.
    number_of_processes += 2;
#endif

    int cur_process_count;
    for (int i = 0; i < 10; ++i) {
      cur_process_count = GetBrowserProcessCount();
      if (cur_process_count == number_of_processes)
        return true;

      PlatformThread::Sleep(sleep_timeout_ms() / 10);
    }

    EXPECT_EQ(number_of_processes, cur_process_count);
    return false;
  }
};

#if defined(OS_LINUX)
// Fails running under valgrind, http://crbug.com/28445
#define SingleWorker DISABLED_SingleWorker
#endif

TEST_F(WorkerTest, SingleWorker) {
  RunTest(L"single_worker.html");
}

TEST_F(WorkerTest, MultipleWorkers) {
  RunTest(L"multi_worker.html");
}

#if defined(OS_LINUX)
#define IncognitoSharedWorkers FLAKY_IncognitoSharedWorkers
#endif

// Incognito windows should not share workers with non-incognito windows
TEST_F(WorkerTest, IncognitoSharedWorkers) {
  // Load a non-incognito tab and have it create a shared worker
  RunTest(L"incognito_worker.html");
  // Incognito worker should not share with non-incognito
  RunIncognitoTest(L"incognito_worker.html");
}

#if defined(OS_LINUX) || defined (OS_MACOSX)
#define WorkerFastLayoutTests DISABLED_WorkerFastLayoutTests
#endif

TEST_F(WorkerTest, WorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "stress-js-execution.html",
    "use-machine-stack.html",
    "worker-call.html",
    "worker-cloneport.html",
    "worker-close.html",
    "worker-constructor.html",
    "worker-context-gc.html",
    "worker-context-multi-port.html",
    "worker-event-listener.html",
    "worker-gc.html",
    // worker-lifecycle.html relies on layoutTestController.workerThreadCount
    // which is not currently implemented.
    // "worker-lifecycle.html",
    "worker-location.html",
    "worker-messageport.html",
    // Disabled after r27089 (WebKit merge), http://crbug.com/22947
    // "worker-messageport-gc.html",
    "worker-multi-port.html",
    "worker-navigator.html",
    "worker-replace-global-constructor.html",
    "worker-replace-self.html",
    "worker-script-error.html",
    "worker-terminate.html",
    "worker-timeout.html"
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);

  // Navigate away from to a blank page so that any workers are cleaned up. This
  // helps leaks trackers do a better job of reporting.
  scoped_refptr<TabProxy> tab(GetActiveTab());
  GURL about_url(std::string("file://localhost/"));
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(about_url));
}

#if defined(OS_WIN) || defined(OS_MACOSX)
// http://crbug.com/27636 - incorrect URL_MISMATCH exceptions sometimes get
// generated on the windows try bots.
// http://crbug.com/28445 - flakiness on mac
#define SharedWorkerFastLayoutTests DISABLED_SharedWorkerFastLayoutTests
#endif

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// These tests are flaky on linux/views builds.
// See http://crbug.com/28808.
#define MessagePorts FLAKY_MessagePorts
#define SharedWorkerFastLayoutTests FLAKY_SharedWorkerFastLayoutTests
#endif

TEST_F(WorkerTest, SharedWorkerFastLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-constructor.html",
    "shared-worker-context-gc.html",
    "shared-worker-event-listener.html",
    "shared-worker-exception.html",
    "shared-worker-gc.html",
    // Lifecycle tests rely on layoutTestController.workerThreadCount which is
    // not currently implemented.
    //"shared-worker-frame-lifecycle.html",
    //"shared-worker-lifecycle.html",
    "shared-worker-load-error.html",
    "shared-worker-location.html",
    "shared-worker-name.html",
    "shared-worker-navigator.html",
    "shared-worker-replace-global-constructor.html",
    "shared-worker-replace-self.html",
    "shared-worker-script-error.html",
    "shared-worker-shared.html",
    "shared-worker-simple.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // Worker tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i) {
    RunLayoutTest(kLayoutTestFiles[i], false);
    // Shared workers will error out if we ever have more than one tab open.
    int window_count = 0;
    ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    ASSERT_EQ(1, window_count);
    EXPECT_EQ(1, GetTabCount());
  }
}

TEST_F(WorkerTest, WorkerHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "shared-worker-importScripts.html",
    "shared-worker-redirect.html",
    // flakey? BUG 16934 "text-encoding.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "worker-importScripts.html",
#endif
    "worker-redirect.html",
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

#if defined(OS_LINUX)
// Fails running under valgrind http://crbug.com/28445
#define WorkerXhrHttpLayoutTests DISABLED_WorkerXhrHttpLayoutTests
#endif

TEST_F(WorkerTest, WorkerXhrHttpLayoutTests) {
  static const char* kLayoutTestFiles[] = {
    "abort-exception-assert.html",
#if defined(OS_WIN)
    // Fails on the mac (and linux?):
    // http://code.google.com/p/chromium/issues/detail?id=22599
    "close.html",
#endif
    // These tests (and the shared-worker versions below) are disabled due to
    // limitations in lighttpd (doesn't handle all of the HTTP methods).
    //"methods-async.html",
    //"methods.html",

    "shared-worker-close.html",
    // Disabled due to limitations in lighttpd (does not handle methods other
    // than GET/PUT/POST).
    //"shared-worker-methods-async.html",
    //"shared-worker-methods.html",
    "shared-worker-xhr-file-not-found.html",

    "xmlhttprequest-file-not-found.html"
  };

  FilePath http_test_dir;
  http_test_dir = http_test_dir.AppendASCII("LayoutTests");
  http_test_dir = http_test_dir.AppendASCII("http");
  http_test_dir = http_test_dir.AppendASCII("tests");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("xmlhttprequest");
  worker_test_dir = worker_test_dir.AppendASCII("workers");
  InitializeForLayoutTest(http_test_dir, worker_test_dir, true);

  StartHttpServer(new_http_root_dir_);
  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], true);
  StopHttpServer();
}

TEST_F(WorkerTest, MessagePorts) {
  static const char* kLayoutTestFiles[] = {
    "message-channel-gc.html",
    "message-channel-gc-2.html",
    "message-channel-gc-3.html",
    "message-channel-gc-4.html",
    "message-port.html",
    "message-port-clone.html",
    "message-port-constructor-for-deleted-document.html",
    "message-port-deleted-document.html",
    "message-port-deleted-frame.html",
    "message-port-inactive-document.html",
    "message-port-multi.html",
    "message-port-no-wrapper.html",
    // Only works with run-webkit-tests --leaks.
    //"message-channel-listener-circular-ownership.html",
  };

  FilePath fast_test_dir;
  fast_test_dir = fast_test_dir.AppendASCII("LayoutTests");
  fast_test_dir = fast_test_dir.AppendASCII("fast");

  FilePath worker_test_dir;
  worker_test_dir = worker_test_dir.AppendASCII("events");
  InitializeForLayoutTest(fast_test_dir, worker_test_dir, false);

  // MessagePort tests also rely on common files in js/resources.
  FilePath js_dir = fast_test_dir.AppendASCII("js");
  FilePath resource_dir;
  resource_dir = resource_dir.AppendASCII("resources");
  AddResourceForLayoutTest(js_dir, resource_dir);

  for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
    RunLayoutTest(kLayoutTestFiles[i], false);
}

// Disable LimitPerPage on Linux. Seems to work on Mac though:
// http://code.google.com/p/chromium/issues/detail?id=22608
#if !defined(OS_LINUX)
// This test fails after WebKit merge 49414:49432. (BUG=24652)
TEST_F(WorkerTest, LimitPerPage) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));

  ASSERT_TRUE(WaitForProcessCountToBe(1, max_workers_per_tab));
}
#endif

#if defined(OS_LINUX)
// Fails (crashes) on Linux Tests: http://crbug.com/28445
#define LimitTotal DISABLED_LimitTotal
#elif defined(OS_MACOSX)
// Doesn't crash, but on Mac it sometimes fails for a few runs in a row,
// http://crbug.com/28445
#define LimitTotal FLAKY_LimitTotal
#endif

TEST_F(WorkerTest, LimitTotal) {
  int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate;
  int total_workers = WorkerService::kMaxWorkersWhenSeparate;

  int tab_count = (total_workers / max_workers_per_tab) + 1;
  GURL url = GetTestUrl(L"workers", L"many_workers.html");
  url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab));

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURL(url));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  for (int i = 1; i < tab_count; ++i)
    window->AppendTab(url);

  // Check that we didn't create more than the max number of workers.
  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));

  // Now close a page and check that the queued workers were started.
  tab->NavigateToURL(GetTestUrl(L"google", L"google.html"));

  ASSERT_TRUE(WaitForProcessCountToBe(tab_count, total_workers));
}
<|endoftext|>


<commit_before>// Copyright 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 "cc/layers/tiled_layer_impl.h"

#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/layers/append_quads_data.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/layer_tiling_data.h"
#include "cc/trees/occlusion_tracker.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/quad_f.h"

namespace cc {

class DrawableTile : public LayerTilingData::Tile {
 public:
  static scoped_ptr<DrawableTile> Create() {
    return make_scoped_ptr(new DrawableTile());
  }

  ResourceProvider::ResourceId resource_id() const { return resource_id_; }
  void set_resource_id(ResourceProvider::ResourceId resource_id) {
    resource_id_ = resource_id;
  }
  bool contents_swizzled() { return contents_swizzled_; }
  void set_contents_swizzled(bool contents_swizzled) {
    contents_swizzled_ = contents_swizzled;
  }

 private:
  DrawableTile() : resource_id_(0), contents_swizzled_(false) {}

  ResourceProvider::ResourceId resource_id_;
  bool contents_swizzled_;

  DISALLOW_COPY_AND_ASSIGN(DrawableTile);
};

TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
    : LayerImpl(tree_impl, id), skips_draw_(true) {}

TiledLayerImpl::~TiledLayerImpl() {
}

ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
  // This function is only valid for single texture layers, e.g. masks.
  DCHECK(tiler_);
  // It's possible the mask layer is created but has no size or otherwise
  // can't draw.
  if (tiler_->num_tiles_x() == 0 || tiler_->num_tiles_y() == 0)
    return 0;

  // Any other number of tiles other than 0 or 1 is incorrect for masks.
  DCHECK_EQ(tiler_->num_tiles_x(), 1);
  DCHECK_EQ(tiler_->num_tiles_y(), 1);

  DrawableTile* tile = TileAt(0, 0);
  ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
  return resource_id;
}

bool TiledLayerImpl::HasTileAt(int i, int j) const {
  return !!tiler_->TileAt(i, j);
}

bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
}

DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
}

DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
  DrawableTile* added_tile = tile.get();
  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);

  return added_tile;
}

void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
                                              float* width) const {
  *color = DebugColors::TiledContentLayerBorderColor();
  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}

scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}

void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
  LayerImpl::AsValueInto(state);
  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
}

size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
  size_t amount = 0;
  const size_t kMemoryUsagePerTileInBytes =
      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    if (!tile || !tile->resource_id())
      continue;
    amount += kMemoryUsagePerTileInBytes;
  }
  return amount;
}

void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);

  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);

  tiled_layer->set_skips_draw(skips_draw_);
  tiled_layer->SetTilingData(*tiler_);

  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    int i = iter->first.first;
    int j = iter->first.second;
    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);

    tiled_layer->PushTileProperties(i,
                                    j,
                                    tile->resource_id(),
                                    tile->opaque_rect(),
                                    tile->contents_swizzled());
  }
}

bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
                              ResourceProvider* resource_provider) {
  if (!tiler_ || tiler_->has_empty_bounds() ||
      visible_content_rect().IsEmpty() ||
      draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    return false;
  return LayerImpl::WillDraw(draw_mode, resource_provider);
}

void TiledLayerImpl::AppendQuads(
    RenderPass* render_pass,
    const OcclusionTracker<LayerImpl>& occlusion_tracker,
    AppendQuadsData* append_quads_data) {
  DCHECK(tiler_);
  DCHECK(!tiler_->has_empty_bounds());
  DCHECK(!visible_content_rect().IsEmpty());

  gfx::Rect content_rect = visible_content_rect();
  SharedQuadState* shared_quad_state =
      render_pass->CreateAndAppendSharedQuadState();
  PopulateSharedQuadState(shared_quad_state);

  AppendDebugBorderQuad(
      render_pass, content_bounds(), shared_quad_state, append_quads_data);

  int left, top, right, bottom;
  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);

  if (ShowDebugBorders()) {
    for (int j = top; j <= bottom; ++j) {
      for (int i = left; i <= right; ++i) {
        DrawableTile* tile = TileAt(i, j);
        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
        gfx::Rect visible_tile_rect = tile_rect;
        SkColor border_color;
        float border_width;

        if (skips_draw_ || !tile || !tile->resource_id()) {
          border_color = DebugColors::MissingTileBorderColor();
          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
        } else {
          border_color = DebugColors::HighResTileBorderColor();
          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
        }
        DebugBorderDrawQuad* debug_border_quad =
            render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
        debug_border_quad->SetNew(shared_quad_state,
                                  tile_rect,
                                  visible_tile_rect,
                                  border_color,
                                  border_width);
      }
    }
  }

  if (skips_draw_)
    return;

  for (int j = top; j <= bottom; ++j) {
    for (int i = left; i <= right; ++i) {
      DrawableTile* tile = TileAt(i, j);
      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
      gfx::Rect display_rect = tile_rect;
      tile_rect.Intersect(content_rect);

      // Skip empty tiles.
      if (tile_rect.IsEmpty())
        continue;

      gfx::Rect visible_tile_rect =
          occlusion_tracker.UnoccludedContentRect(tile_rect, draw_transform());
      if (visible_tile_rect.IsEmpty())
        continue;

      if (!tile || !tile->resource_id()) {
        SkColor checker_color;
        if (ShowDebugBorders()) {
          checker_color =
              tile ? DebugColors::InvalidatedTileCheckerboardColor()
                   : DebugColors::EvictedTileCheckerboardColor();
        } else {
          checker_color = DebugColors::DefaultCheckerboardColor();
        }

        CheckerboardDrawQuad* checkerboard_quad =
            render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
        checkerboard_quad->SetNew(
            shared_quad_state, tile_rect, visible_tile_rect, checker_color);
        append_quads_data->num_missing_tiles++;
        continue;
      }

      gfx::Rect tile_opaque_rect =
          contents_opaque() ? tile_rect : gfx::IntersectRects(
                                              tile->opaque_rect(), tile_rect);

      // Keep track of how the top left has moved, so the texture can be
      // offset the same amount.
      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
      gfx::Vector2d texture_offset =
          tiler_->texture_offset(i, j) + display_offset;
      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;

      float tile_width = static_cast<float>(tiler_->tile_size().width());
      float tile_height = static_cast<float>(tiler_->tile_size().height());
      gfx::Size texture_size(tile_width, tile_height);

      TileDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
      quad->SetNew(shared_quad_state,
                   tile_rect,
                   tile_opaque_rect,
                   visible_tile_rect,
                   tile->resource_id(),
                   tex_coord_rect,
                   texture_size,
                   tile->contents_swizzled());
    }
  }
}

void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
  if (tiler_) {
    tiler_->reset();
  } else {
    tiler_ = LayerTilingData::Create(tiler.tile_size(),
                                     tiler.has_border_texels()
                                         ? LayerTilingData::HAS_BORDER_TEXELS
                                         : LayerTilingData::NO_BORDER_TEXELS);
  }
  *tiler_ = tiler;
}

void TiledLayerImpl::PushTileProperties(
    int i,
    int j,
    ResourceProvider::ResourceId resource_id,
    const gfx::Rect& opaque_rect,
    bool contents_swizzled) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(resource_id);
  tile->set_opaque_rect(opaque_rect);
  tile->set_contents_swizzled(contents_swizzled);
}

void TiledLayerImpl::PushInvalidTile(int i, int j) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(0);
  tile->set_opaque_rect(gfx::Rect());
  tile->set_contents_swizzled(false);
}

Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
  if (skips_draw_)
    return Region();
  if (contents_opaque())
    return visible_content_rect();
  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
}

void TiledLayerImpl::ReleaseResources() {
  tiler_->reset();
}

const char* TiledLayerImpl::LayerTypeAsString() const {
  return "cc::TiledLayerImpl";
}

}  // namespace cc
<commit_msg>cc: add DCHECKs of tile in GPUMemoryUsageInBytes and PushPropertiesTo<commit_after>// Copyright 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 "cc/layers/tiled_layer_impl.h"

#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/layers/append_quads_data.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/layer_tiling_data.h"
#include "cc/trees/occlusion_tracker.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/quad_f.h"

namespace cc {

class DrawableTile : public LayerTilingData::Tile {
 public:
  static scoped_ptr<DrawableTile> Create() {
    return make_scoped_ptr(new DrawableTile());
  }

  ResourceProvider::ResourceId resource_id() const { return resource_id_; }
  void set_resource_id(ResourceProvider::ResourceId resource_id) {
    resource_id_ = resource_id;
  }
  bool contents_swizzled() { return contents_swizzled_; }
  void set_contents_swizzled(bool contents_swizzled) {
    contents_swizzled_ = contents_swizzled;
  }

 private:
  DrawableTile() : resource_id_(0), contents_swizzled_(false) {}

  ResourceProvider::ResourceId resource_id_;
  bool contents_swizzled_;

  DISALLOW_COPY_AND_ASSIGN(DrawableTile);
};

TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
    : LayerImpl(tree_impl, id), skips_draw_(true) {}

TiledLayerImpl::~TiledLayerImpl() {
}

ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
  // This function is only valid for single texture layers, e.g. masks.
  DCHECK(tiler_);
  // It's possible the mask layer is created but has no size or otherwise
  // can't draw.
  if (tiler_->num_tiles_x() == 0 || tiler_->num_tiles_y() == 0)
    return 0;

  // Any other number of tiles other than 0 or 1 is incorrect for masks.
  DCHECK_EQ(tiler_->num_tiles_x(), 1);
  DCHECK_EQ(tiler_->num_tiles_y(), 1);

  DrawableTile* tile = TileAt(0, 0);
  ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
  return resource_id;
}

bool TiledLayerImpl::HasTileAt(int i, int j) const {
  return !!tiler_->TileAt(i, j);
}

bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
}

DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
}

DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
  DrawableTile* added_tile = tile.get();
  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);

  return added_tile;
}

void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
                                              float* width) const {
  *color = DebugColors::TiledContentLayerBorderColor();
  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}

scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}

void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
  LayerImpl::AsValueInto(state);
  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
}

size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
  size_t amount = 0;
  const size_t kMemoryUsagePerTileInBytes =
      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    DCHECK(tile);
    if (!tile->resource_id())
      continue;
    amount += kMemoryUsagePerTileInBytes;
  }
  return amount;
}

void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
  LayerImpl::PushPropertiesTo(layer);

  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);

  tiled_layer->set_skips_draw(skips_draw_);
  tiled_layer->SetTilingData(*tiler_);

  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
       iter != tiler_->tiles().end();
       ++iter) {
    int i = iter->first.first;
    int j = iter->first.second;
    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    DCHECK(tile);
    tiled_layer->PushTileProperties(i,
                                    j,
                                    tile->resource_id(),
                                    tile->opaque_rect(),
                                    tile->contents_swizzled());
  }
}

bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
                              ResourceProvider* resource_provider) {
  if (!tiler_ || tiler_->has_empty_bounds() ||
      visible_content_rect().IsEmpty() ||
      draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    return false;
  return LayerImpl::WillDraw(draw_mode, resource_provider);
}

void TiledLayerImpl::AppendQuads(
    RenderPass* render_pass,
    const OcclusionTracker<LayerImpl>& occlusion_tracker,
    AppendQuadsData* append_quads_data) {
  DCHECK(tiler_);
  DCHECK(!tiler_->has_empty_bounds());
  DCHECK(!visible_content_rect().IsEmpty());

  gfx::Rect content_rect = visible_content_rect();
  SharedQuadState* shared_quad_state =
      render_pass->CreateAndAppendSharedQuadState();
  PopulateSharedQuadState(shared_quad_state);

  AppendDebugBorderQuad(
      render_pass, content_bounds(), shared_quad_state, append_quads_data);

  int left, top, right, bottom;
  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);

  if (ShowDebugBorders()) {
    for (int j = top; j <= bottom; ++j) {
      for (int i = left; i <= right; ++i) {
        DrawableTile* tile = TileAt(i, j);
        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
        gfx::Rect visible_tile_rect = tile_rect;
        SkColor border_color;
        float border_width;

        if (skips_draw_ || !tile || !tile->resource_id()) {
          border_color = DebugColors::MissingTileBorderColor();
          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
        } else {
          border_color = DebugColors::HighResTileBorderColor();
          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
        }
        DebugBorderDrawQuad* debug_border_quad =
            render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
        debug_border_quad->SetNew(shared_quad_state,
                                  tile_rect,
                                  visible_tile_rect,
                                  border_color,
                                  border_width);
      }
    }
  }

  if (skips_draw_)
    return;

  for (int j = top; j <= bottom; ++j) {
    for (int i = left; i <= right; ++i) {
      DrawableTile* tile = TileAt(i, j);
      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
      gfx::Rect display_rect = tile_rect;
      tile_rect.Intersect(content_rect);

      // Skip empty tiles.
      if (tile_rect.IsEmpty())
        continue;

      gfx::Rect visible_tile_rect =
          occlusion_tracker.UnoccludedContentRect(tile_rect, draw_transform());
      if (visible_tile_rect.IsEmpty())
        continue;

      if (!tile || !tile->resource_id()) {
        SkColor checker_color;
        if (ShowDebugBorders()) {
          checker_color =
              tile ? DebugColors::InvalidatedTileCheckerboardColor()
                   : DebugColors::EvictedTileCheckerboardColor();
        } else {
          checker_color = DebugColors::DefaultCheckerboardColor();
        }

        CheckerboardDrawQuad* checkerboard_quad =
            render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
        checkerboard_quad->SetNew(
            shared_quad_state, tile_rect, visible_tile_rect, checker_color);
        append_quads_data->num_missing_tiles++;
        continue;
      }

      gfx::Rect tile_opaque_rect =
          contents_opaque() ? tile_rect : gfx::IntersectRects(
                                              tile->opaque_rect(), tile_rect);

      // Keep track of how the top left has moved, so the texture can be
      // offset the same amount.
      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
      gfx::Vector2d texture_offset =
          tiler_->texture_offset(i, j) + display_offset;
      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;

      float tile_width = static_cast<float>(tiler_->tile_size().width());
      float tile_height = static_cast<float>(tiler_->tile_size().height());
      gfx::Size texture_size(tile_width, tile_height);

      TileDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
      quad->SetNew(shared_quad_state,
                   tile_rect,
                   tile_opaque_rect,
                   visible_tile_rect,
                   tile->resource_id(),
                   tex_coord_rect,
                   texture_size,
                   tile->contents_swizzled());
    }
  }
}

void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
  if (tiler_) {
    tiler_->reset();
  } else {
    tiler_ = LayerTilingData::Create(tiler.tile_size(),
                                     tiler.has_border_texels()
                                         ? LayerTilingData::HAS_BORDER_TEXELS
                                         : LayerTilingData::NO_BORDER_TEXELS);
  }
  *tiler_ = tiler;
}

void TiledLayerImpl::PushTileProperties(
    int i,
    int j,
    ResourceProvider::ResourceId resource_id,
    const gfx::Rect& opaque_rect,
    bool contents_swizzled) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(resource_id);
  tile->set_opaque_rect(opaque_rect);
  tile->set_contents_swizzled(contents_swizzled);
}

void TiledLayerImpl::PushInvalidTile(int i, int j) {
  DrawableTile* tile = TileAt(i, j);
  if (!tile)
    tile = CreateTile(i, j);
  tile->set_resource_id(0);
  tile->set_opaque_rect(gfx::Rect());
  tile->set_contents_swizzled(false);
}

Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
  if (skips_draw_)
    return Region();
  if (contents_opaque())
    return visible_content_rect();
  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
}

void TiledLayerImpl::ReleaseResources() {
  tiler_->reset();
}

const char* TiledLayerImpl::LayerTypeAsString() const {
  return "cc::TiledLayerImpl";
}

}  // namespace cc
<|endoftext|>