<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 <map>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/test/test_timeouts.h"
#include "base/test/trace_event_analyzer.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/perf/perf_test.h"
#include "chrome/test/ui/javascript_test_util.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_implementation.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

enum FrameRateTestFlags {
  kUseGpu             = 1 << 0, // Only execute test if --enable-gpu, and verify
                                // that test ran on GPU. This is required for
                                // tests that run on GPU.
  kForceGpuComposited = 1 << 1, // Force the test to use the compositor.
  kDisableVsync       = 1 << 2, // Do not limit framerate to vertical refresh.
                                // when on GPU, nor to 60hz when not on GPU.
  kUseReferenceBuild  = 1 << 3, // Run test using the reference chrome build.
  kInternal           = 1 << 4, // Test uses internal test data.
  kHasRedirect        = 1 << 5, // Test page contains an HTML redirect.
};

class FrameRateTest
  : public UIPerfTest
  , public ::testing::WithParamInterface<int> {
 public:
  FrameRateTest() {
    show_window_ = true;
    dom_automation_enabled_ = true;
  }

  bool HasFlag(FrameRateTestFlags flag) const {
    return (GetParam() & flag) == flag;
  }

  bool IsGpuAvailable() const {
    return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
  }

  std::string GetSuffixForTestFlags() {
    std::string suffix;
    if (HasFlag(kForceGpuComposited))
      suffix += "_comp";
    if (HasFlag(kUseGpu))
      suffix += "_gpu";
    if (HasFlag(kDisableVsync))
      suffix += "_novsync";
    if (HasFlag(kUseReferenceBuild))
      suffix += "_ref";
    return suffix;
  }

  virtual FilePath GetDataPath(const std::string& name) {
    // Make sure the test data is checked out.
    FilePath test_path;
    PathService::Get(chrome::DIR_TEST_DATA, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("perf"));
    test_path = test_path.Append(FILE_PATH_LITERAL("frame_rate"));
    if (HasFlag(kInternal)) {
      test_path = test_path.Append(FILE_PATH_LITERAL("private"));
    } else {
      test_path = test_path.Append(FILE_PATH_LITERAL("content"));
    }
    test_path = test_path.AppendASCII(name);
    return test_path;
  }

  virtual void SetUp() {
    if (HasFlag(kUseReferenceBuild))
      UseReferenceBuild();

    // Turn on chrome.Interval to get higher-resolution timestamps on frames.
    launch_arguments_.AppendSwitch(switches::kEnableBenchmarking);

    // Required additional argument to make the kEnableBenchmarking switch work.
    launch_arguments_.AppendSwitch(switches::kEnableStatsTable);

    // UI tests boot up render views starting from about:blank. This causes
    // the renderer to start up thinking it cannot use the GPU. To work
    // around that, and allow the frame rate test to use the GPU, we must
    // pass kAllowWebUICompositing.
    launch_arguments_.AppendSwitch(switches::kAllowWebUICompositing);

    // Some of the tests may launch http requests through JSON or AJAX
    // which causes a security error (cross domain request) when the page
    // is loaded from the local file system ( file:// ). The following switch
    // fixes that error.
    launch_arguments_.AppendSwitch(switches::kAllowFileAccessFromFiles);

    if (!HasFlag(kUseGpu)) {
      launch_arguments_.AppendSwitch(switches::kDisableAcceleratedCompositing);
      launch_arguments_.AppendSwitch(switches::kDisableExperimentalWebGL);
      launch_arguments_.AppendSwitch(switches::kDisableAccelerated2dCanvas);
    } else {
      // This switch is required for enabling the accelerated 2d canvas on
      // Chrome versions prior to Chrome 15, which may be the case for the
      // reference build.
      launch_arguments_.AppendSwitch(switches::kEnableAccelerated2dCanvas);
    }

    if (HasFlag(kDisableVsync))
      launch_arguments_.AppendSwitch(switches::kDisableGpuVsync);

    UIPerfTest::SetUp();
  }

  bool DidRunOnGpu(const std::string& json_events) {
    using namespace trace_analyzer;

    // Check trace for GPU accleration.
    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));

    gfx::GLImplementation gl_impl = gfx::kGLImplementationNone;
    const TraceEvent* gpu_event = analyzer->FindOneEvent(
        Query(EVENT_NAME) == Query::String("SwapBuffers") &&
        Query(EVENT_HAS_NUMBER_ARG, "GLImpl"));
    if (gpu_event)
      gl_impl = static_cast<gfx::GLImplementation>(
          gpu_event->GetKnownArgAsInt("GLImpl"));
    return (gl_impl == gfx::kGLImplementationDesktopGL ||
            gl_impl == gfx::kGLImplementationEGLGLES2);
  }

  void RunTest(const std::string& name) {
    if (HasFlag(kUseGpu) && !IsGpuAvailable()) {
      printf("Test skipped: requires gpu. Pass --enable-gpu on the command "
             "line if use of GPU is desired.\n");
      return;
    }

    // Verify flag combinations.
    ASSERT_TRUE(HasFlag(kUseGpu) || !HasFlag(kForceGpuComposited));
    ASSERT_TRUE(!HasFlag(kUseGpu) || IsGpuAvailable());

    FilePath test_path = GetDataPath(name);
    ASSERT_TRUE(file_util::DirectoryExists(test_path))
        << "Missing test directory: " << test_path.value();

    test_path = test_path.Append(FILE_PATH_LITERAL("test.html"));

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

    // TODO(jbates): remove this check when ref builds are updated.
    if (!HasFlag(kUseReferenceBuild))
      ASSERT_TRUE(automation()->BeginTracing("test_gpu"));

    if (HasFlag(kHasRedirect)) {
      // If the test file is known to contain an html redirect, we must block
      // until the second navigation is complete and reacquire the active tab
      // in order to avoid a race condition.
      // If the following assertion is triggered due to a timeout, it is
      // possible that the current test does not re-direct and therefore should
      // not have the kHasRedirect flag turned on.
      ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
        tab->NavigateToURLBlockUntilNavigationsComplete(
        net::FilePathToFileURL(test_path), 2));
      tab = GetActiveTab();
      ASSERT_TRUE(tab.get());
    } else {
      ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
        tab->NavigateToURL(net::FilePathToFileURL(test_path)));
    }

    // Block until initialization completes
    // If the following assertion fails intermittently, it could be due to a
    // race condition caused by an html redirect. If that is the case, verify
    // that flag kHasRedirect is enabled for the current test.
    ASSERT_TRUE(WaitUntilJavaScriptCondition(
      tab, L"", L"window.domAutomationController.send(__initialized);",
      TestTimeouts::large_test_timeout_ms()));

    if (HasFlag(kForceGpuComposited)) {
      ASSERT_TRUE(tab->NavigateToURLAsync(
        GURL("javascript:__make_body_composited();")));
    }

    // Start the tests.
    ASSERT_TRUE(tab->NavigateToURLAsync(GURL("javascript:__start_all();")));

    // Block until the tests completes.
    ASSERT_TRUE(WaitUntilJavaScriptCondition(
        tab, L"", L"window.domAutomationController.send(!__running_all);",
        TestTimeouts::large_test_timeout_ms()));

    // TODO(jbates): remove this check when ref builds are updated.
    if (!HasFlag(kUseReferenceBuild)) {
      std::string json_events;
      ASSERT_TRUE(automation()->EndTracing(&json_events));

      bool did_run_on_gpu = DidRunOnGpu(json_events);
      bool expect_gpu = HasFlag(kUseGpu);
      EXPECT_EQ(expect_gpu, did_run_on_gpu);
    }

    // Read out the results.
    std::wstring json;
    ASSERT_TRUE(tab->ExecuteAndExtractString(
        L"",
        L"window.domAutomationController.send("
        L"JSON.stringify(__calc_results_total()));",
        &json));

    std::map<std::string, std::string> results;
    ASSERT_TRUE(JsonDictionaryToMap(WideToUTF8(json), &results));

    ASSERT_TRUE(results.find("mean") != results.end());
    ASSERT_TRUE(results.find("sigma") != results.end());
    ASSERT_TRUE(results.find("gestures") != results.end());
    ASSERT_TRUE(results.find("means") != results.end());
    ASSERT_TRUE(results.find("sigmas") != results.end());

    std::string trace_name = "interval" + GetSuffixForTestFlags();
    printf("GESTURES %s: %s= [%s] [%s] [%s]\n", name.c_str(),
                                                trace_name.c_str(),
                                                results["gestures"].c_str(),
                                                results["means"].c_str(),
                                                results["sigmas"].c_str());

    std::string mean_and_error = results["mean"] + "," + results["sigma"];
    perf_test::PrintResultMeanAndError(name, "", trace_name, mean_and_error,
                                       "frames-per-second", true);
  }
};

// Must use a different class name to avoid test instantiation conflicts
// with FrameRateTest. An alias is good enough. The alias names must match
// the pattern FrameRate*Test* for them to get picked up by the test bots.
typedef FrameRateTest FrameRateCompositingTest;

// Tests that trigger compositing with a -webkit-translateZ(0)
#define FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(content) \
TEST_P(FrameRateCompositingTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateCompositingTest, ::testing::Values(
                        0,
                        kUseGpu | kForceGpuComposited,
                        kUseReferenceBuild,
                        kUseReferenceBuild | kUseGpu | kForceGpuComposited));

FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(blank);
FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(googleblog);

typedef FrameRateTest FrameRateNoVsyncCanvasInternalTest;

// Tests for animated 2D canvas content with and without disabling vsync
#define INTERNAL_FRAME_RATE_TEST_CANVAS_WITH_AND_WITHOUT_NOVSYNC(content) \
TEST_P(FrameRateNoVsyncCanvasInternalTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateNoVsyncCanvasInternalTest, ::testing::Values(
    kInternal | kHasRedirect,
    kInternal | kHasRedirect | kUseGpu,
    kInternal | kHasRedirect | kUseGpu | kDisableVsync,
    kUseReferenceBuild | kInternal | kHasRedirect,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu | kDisableVsync));

INTERNAL_FRAME_RATE_TEST_CANVAS_WITH_AND_WITHOUT_NOVSYNC(fishbowl)

typedef FrameRateTest FrameRateGpuCanvasInternalTest;

// Tests for animated 2D canvas content to be tested only with GPU
// acceleration.
// tests are run with and without Vsync
#define INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(content) \
TEST_P(FrameRateGpuCanvasInternalTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateGpuCanvasInternalTest, ::testing::Values(
    kInternal | kHasRedirect | kUseGpu,
    kInternal | kHasRedirect | kUseGpu | kDisableVsync,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu | kDisableVsync));

INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(fireflies)
INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(FishIE)
INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(speedreading)

}  // namespace
<commit_msg>Fix units string for Frame Rate tests (should now be milliseconds-per-frame)<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 <map>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/test/test_timeouts.h"
#include "base/test/trace_event_analyzer.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/perf/perf_test.h"
#include "chrome/test/ui/javascript_test_util.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_implementation.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

enum FrameRateTestFlags {
  kUseGpu             = 1 << 0, // Only execute test if --enable-gpu, and verify
                                // that test ran on GPU. This is required for
                                // tests that run on GPU.
  kForceGpuComposited = 1 << 1, // Force the test to use the compositor.
  kDisableVsync       = 1 << 2, // Do not limit framerate to vertical refresh.
                                // when on GPU, nor to 60hz when not on GPU.
  kUseReferenceBuild  = 1 << 3, // Run test using the reference chrome build.
  kInternal           = 1 << 4, // Test uses internal test data.
  kHasRedirect        = 1 << 5, // Test page contains an HTML redirect.
};

class FrameRateTest
  : public UIPerfTest
  , public ::testing::WithParamInterface<int> {
 public:
  FrameRateTest() {
    show_window_ = true;
    dom_automation_enabled_ = true;
  }

  bool HasFlag(FrameRateTestFlags flag) const {
    return (GetParam() & flag) == flag;
  }

  bool IsGpuAvailable() const {
    return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
  }

  std::string GetSuffixForTestFlags() {
    std::string suffix;
    if (HasFlag(kForceGpuComposited))
      suffix += "_comp";
    if (HasFlag(kUseGpu))
      suffix += "_gpu";
    if (HasFlag(kDisableVsync))
      suffix += "_novsync";
    if (HasFlag(kUseReferenceBuild))
      suffix += "_ref";
    return suffix;
  }

  virtual FilePath GetDataPath(const std::string& name) {
    // Make sure the test data is checked out.
    FilePath test_path;
    PathService::Get(chrome::DIR_TEST_DATA, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("perf"));
    test_path = test_path.Append(FILE_PATH_LITERAL("frame_rate"));
    if (HasFlag(kInternal)) {
      test_path = test_path.Append(FILE_PATH_LITERAL("private"));
    } else {
      test_path = test_path.Append(FILE_PATH_LITERAL("content"));
    }
    test_path = test_path.AppendASCII(name);
    return test_path;
  }

  virtual void SetUp() {
    if (HasFlag(kUseReferenceBuild))
      UseReferenceBuild();

    // Turn on chrome.Interval to get higher-resolution timestamps on frames.
    launch_arguments_.AppendSwitch(switches::kEnableBenchmarking);

    // Required additional argument to make the kEnableBenchmarking switch work.
    launch_arguments_.AppendSwitch(switches::kEnableStatsTable);

    // UI tests boot up render views starting from about:blank. This causes
    // the renderer to start up thinking it cannot use the GPU. To work
    // around that, and allow the frame rate test to use the GPU, we must
    // pass kAllowWebUICompositing.
    launch_arguments_.AppendSwitch(switches::kAllowWebUICompositing);

    // Some of the tests may launch http requests through JSON or AJAX
    // which causes a security error (cross domain request) when the page
    // is loaded from the local file system ( file:// ). The following switch
    // fixes that error.
    launch_arguments_.AppendSwitch(switches::kAllowFileAccessFromFiles);

    if (!HasFlag(kUseGpu)) {
      launch_arguments_.AppendSwitch(switches::kDisableAcceleratedCompositing);
      launch_arguments_.AppendSwitch(switches::kDisableExperimentalWebGL);
      launch_arguments_.AppendSwitch(switches::kDisableAccelerated2dCanvas);
    } else {
      // This switch is required for enabling the accelerated 2d canvas on
      // Chrome versions prior to Chrome 15, which may be the case for the
      // reference build.
      launch_arguments_.AppendSwitch(switches::kEnableAccelerated2dCanvas);
    }

    if (HasFlag(kDisableVsync))
      launch_arguments_.AppendSwitch(switches::kDisableGpuVsync);

    UIPerfTest::SetUp();
  }

  bool DidRunOnGpu(const std::string& json_events) {
    using namespace trace_analyzer;

    // Check trace for GPU accleration.
    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));

    gfx::GLImplementation gl_impl = gfx::kGLImplementationNone;
    const TraceEvent* gpu_event = analyzer->FindOneEvent(
        Query(EVENT_NAME) == Query::String("SwapBuffers") &&
        Query(EVENT_HAS_NUMBER_ARG, "GLImpl"));
    if (gpu_event)
      gl_impl = static_cast<gfx::GLImplementation>(
          gpu_event->GetKnownArgAsInt("GLImpl"));
    return (gl_impl == gfx::kGLImplementationDesktopGL ||
            gl_impl == gfx::kGLImplementationEGLGLES2);
  }

  void RunTest(const std::string& name) {
    if (HasFlag(kUseGpu) && !IsGpuAvailable()) {
      printf("Test skipped: requires gpu. Pass --enable-gpu on the command "
             "line if use of GPU is desired.\n");
      return;
    }

    // Verify flag combinations.
    ASSERT_TRUE(HasFlag(kUseGpu) || !HasFlag(kForceGpuComposited));
    ASSERT_TRUE(!HasFlag(kUseGpu) || IsGpuAvailable());

    FilePath test_path = GetDataPath(name);
    ASSERT_TRUE(file_util::DirectoryExists(test_path))
        << "Missing test directory: " << test_path.value();

    test_path = test_path.Append(FILE_PATH_LITERAL("test.html"));

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

    // TODO(jbates): remove this check when ref builds are updated.
    if (!HasFlag(kUseReferenceBuild))
      ASSERT_TRUE(automation()->BeginTracing("test_gpu"));

    if (HasFlag(kHasRedirect)) {
      // If the test file is known to contain an html redirect, we must block
      // until the second navigation is complete and reacquire the active tab
      // in order to avoid a race condition.
      // If the following assertion is triggered due to a timeout, it is
      // possible that the current test does not re-direct and therefore should
      // not have the kHasRedirect flag turned on.
      ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
        tab->NavigateToURLBlockUntilNavigationsComplete(
        net::FilePathToFileURL(test_path), 2));
      tab = GetActiveTab();
      ASSERT_TRUE(tab.get());
    } else {
      ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
        tab->NavigateToURL(net::FilePathToFileURL(test_path)));
    }

    // Block until initialization completes
    // If the following assertion fails intermittently, it could be due to a
    // race condition caused by an html redirect. If that is the case, verify
    // that flag kHasRedirect is enabled for the current test.
    ASSERT_TRUE(WaitUntilJavaScriptCondition(
      tab, L"", L"window.domAutomationController.send(__initialized);",
      TestTimeouts::large_test_timeout_ms()));

    if (HasFlag(kForceGpuComposited)) {
      ASSERT_TRUE(tab->NavigateToURLAsync(
        GURL("javascript:__make_body_composited();")));
    }

    // Start the tests.
    ASSERT_TRUE(tab->NavigateToURLAsync(GURL("javascript:__start_all();")));

    // Block until the tests completes.
    ASSERT_TRUE(WaitUntilJavaScriptCondition(
        tab, L"", L"window.domAutomationController.send(!__running_all);",
        TestTimeouts::large_test_timeout_ms()));

    // TODO(jbates): remove this check when ref builds are updated.
    if (!HasFlag(kUseReferenceBuild)) {
      std::string json_events;
      ASSERT_TRUE(automation()->EndTracing(&json_events));

      bool did_run_on_gpu = DidRunOnGpu(json_events);
      bool expect_gpu = HasFlag(kUseGpu);
      EXPECT_EQ(expect_gpu, did_run_on_gpu);
    }

    // Read out the results.
    std::wstring json;
    ASSERT_TRUE(tab->ExecuteAndExtractString(
        L"",
        L"window.domAutomationController.send("
        L"JSON.stringify(__calc_results_total()));",
        &json));

    std::map<std::string, std::string> results;
    ASSERT_TRUE(JsonDictionaryToMap(WideToUTF8(json), &results));

    ASSERT_TRUE(results.find("mean") != results.end());
    ASSERT_TRUE(results.find("sigma") != results.end());
    ASSERT_TRUE(results.find("gestures") != results.end());
    ASSERT_TRUE(results.find("means") != results.end());
    ASSERT_TRUE(results.find("sigmas") != results.end());

    std::string trace_name = "interval" + GetSuffixForTestFlags();
    printf("GESTURES %s: %s= [%s] [%s] [%s]\n", name.c_str(),
                                                trace_name.c_str(),
                                                results["gestures"].c_str(),
                                                results["means"].c_str(),
                                                results["sigmas"].c_str());

    std::string mean_and_error = results["mean"] + "," + results["sigma"];
    perf_test::PrintResultMeanAndError(name, "", trace_name, mean_and_error,
                                       "milliseconds-per-frame", true);
  }
};

// Must use a different class name to avoid test instantiation conflicts
// with FrameRateTest. An alias is good enough. The alias names must match
// the pattern FrameRate*Test* for them to get picked up by the test bots.
typedef FrameRateTest FrameRateCompositingTest;

// Tests that trigger compositing with a -webkit-translateZ(0)
#define FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(content) \
TEST_P(FrameRateCompositingTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateCompositingTest, ::testing::Values(
                        0,
                        kUseGpu | kForceGpuComposited,
                        kUseReferenceBuild,
                        kUseReferenceBuild | kUseGpu | kForceGpuComposited));

FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(blank);
FRAME_RATE_TEST_WITH_AND_WITHOUT_ACCELERATED_COMPOSITING(googleblog);

typedef FrameRateTest FrameRateNoVsyncCanvasInternalTest;

// Tests for animated 2D canvas content with and without disabling vsync
#define INTERNAL_FRAME_RATE_TEST_CANVAS_WITH_AND_WITHOUT_NOVSYNC(content) \
TEST_P(FrameRateNoVsyncCanvasInternalTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateNoVsyncCanvasInternalTest, ::testing::Values(
    kInternal | kHasRedirect,
    kInternal | kHasRedirect | kUseGpu,
    kInternal | kHasRedirect | kUseGpu | kDisableVsync,
    kUseReferenceBuild | kInternal | kHasRedirect,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu | kDisableVsync));

INTERNAL_FRAME_RATE_TEST_CANVAS_WITH_AND_WITHOUT_NOVSYNC(fishbowl)

typedef FrameRateTest FrameRateGpuCanvasInternalTest;

// Tests for animated 2D canvas content to be tested only with GPU
// acceleration.
// tests are run with and without Vsync
#define INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(content) \
TEST_P(FrameRateGpuCanvasInternalTest, content) { \
  RunTest(#content); \
}

INSTANTIATE_TEST_CASE_P(, FrameRateGpuCanvasInternalTest, ::testing::Values(
    kInternal | kHasRedirect | kUseGpu,
    kInternal | kHasRedirect | kUseGpu | kDisableVsync,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu,
    kUseReferenceBuild | kInternal | kHasRedirect | kUseGpu | kDisableVsync));

INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(fireflies)
INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(FishIE)
INTERNAL_FRAME_RATE_TEST_CANVAS_GPU(speedreading)

}  // namespace
<|endoftext|>


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

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

#define NUMBER_OF_ITERATIONS 5

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
// Usage Flags: -enable-logging -dump-histograms-on-exit -log-level=0
class TabSwitchingUITest : public UITest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void RunTabSwitchingUITest() {
    // Create a browser proxy.
    browser_proxy_ = automation()->GetBrowserWindow(0);

    // Open all the tabs.
    int initial_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
    int new_tab_count = OpenTabs();
    ASSERT_TRUE(browser_proxy_->WaitForTabCountToBecome(
        initial_tab_count + new_tab_count, 10000));

    // Switch linearly between tabs.
    browser_proxy_->ActivateTab(0);
    int final_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
    for (int i = initial_tab_count; i < final_tab_count; ++i) {
      browser_proxy_->ActivateTab(i);
      ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(i, 10000));
    }

    // Close the browser to force a dump of log.
    bool application_closed = false;
    EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

    // Now open the corresponding log file and collect average and std dev from
    // the histogram stats generated for RenderWidgetHostHWND_WhiteoutDuration
    FilePath log_file_name;
    ASSERT_TRUE(PathService::Get(chrome::DIR_LOGS, &log_file_name));
    log_file_name = log_file_name.AppendASCII("chrome_debug.log");

    bool log_has_been_dumped = false;
    std::string contents;
    int max_tries = 20;
    do {
      log_has_been_dumped = file_util::ReadFileToString(log_file_name,
                                                        &contents);
      if (!log_has_been_dumped)
        PlatformThread::Sleep(100);
    } while (!log_has_been_dumped && max_tries--);
    ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

    // Parse the contents to get average and std deviation.
    std::string average("0.0"), std_dev("0.0");
    const std::string average_str("average = ");
    const std::string std_dev_str("standard deviation = ");
    std::string::size_type pos = contents.find(
        "Histogram: MPArch.RWHH_WhiteoutDuration", 0);
    std::string::size_type comma_pos;
    std::string::size_type number_length;
    if (pos != std::string::npos) {
      // Get the average.
      pos = contents.find(average_str, pos);
      comma_pos = contents.find(",", pos);
      pos += average_str.length();
      number_length = comma_pos - pos;
      average = contents.substr(pos, number_length);

      // Get the std dev.
      pos = contents.find(std_dev_str, pos);
      pos += std_dev_str.length();
      comma_pos = contents.find(" ", pos);
      number_length = comma_pos - pos;
      std_dev = contents.substr(pos, number_length);
    } else {
      LOG(WARNING) << "Histogram: MPArch.RWHH_WhiteoutDuration wasn't found";
    }

    // Print the average and standard deviation.
    PrintResultMeanAndError("tab_switch", "", "t",
                            average + ", " + std_dev, "ms",
                            true /* important */);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

TEST_F(TabSwitchingUITest, GenerateTabSwitchStats) {
  RunTabSwitchingUITest();
}

}  // namespace
<commit_msg>Use TabSwitchPaintDuration in tab switching test.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

#define NUMBER_OF_ITERATIONS 5

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
// Usage Flags: --enable-logging --dump-histograms-on-exit --log-level=0
class TabSwitchingUITest : public UITest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void RunTabSwitchingUITest() {
    // Create a browser proxy.
    browser_proxy_ = automation()->GetBrowserWindow(0);

    // Open all the tabs.
    int initial_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
    int new_tab_count = OpenTabs();
    ASSERT_TRUE(browser_proxy_->WaitForTabCountToBecome(
        initial_tab_count + new_tab_count, 10000));

    // Switch linearly between tabs.
    browser_proxy_->ActivateTab(0);
    int final_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
    for (int i = initial_tab_count; i < final_tab_count; ++i) {
      browser_proxy_->ActivateTab(i);
      ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(i, 10000));
    }

    // Close the browser to force a dump of log.
    bool application_closed = false;
    EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

    // Now open the corresponding log file and collect average and std dev from
    // the histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration
    FilePath log_file_name;
    ASSERT_TRUE(PathService::Get(chrome::DIR_LOGS, &log_file_name));
    log_file_name = log_file_name.AppendASCII("chrome_debug.log");

    bool log_has_been_dumped = false;
    std::string contents;
    int max_tries = 20;
    do {
      log_has_been_dumped = file_util::ReadFileToString(log_file_name,
                                                        &contents);
      if (!log_has_been_dumped)
        PlatformThread::Sleep(100);
    } while (!log_has_been_dumped && max_tries--);
    ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

    // Parse the contents to get average and std deviation.
    std::string average("0.0"), std_dev("0.0");
    const std::string average_str("average = ");
    const std::string std_dev_str("standard deviation = ");
    std::string::size_type pos = contents.find(
        "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0);
    std::string::size_type comma_pos;
    std::string::size_type number_length;

    ASSERT_NE(pos, std::string::npos) <<
      "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" <<
      contents;

    // Get the average.
    pos = contents.find(average_str, pos);
    comma_pos = contents.find(",", pos);
    pos += average_str.length();
    number_length = comma_pos - pos;
    average = contents.substr(pos, number_length);

    // Get the std dev.
    pos = contents.find(std_dev_str, pos);
    pos += std_dev_str.length();
    comma_pos = contents.find(" ", pos);
    number_length = comma_pos - pos;
    std_dev = contents.substr(pos, number_length);

    // Print the average and standard deviation.
    PrintResultMeanAndError("tab_switch", "", "t",
                            average + ", " + std_dev, "ms",
                            true /* important */);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

TEST_F(TabSwitchingUITest, GenerateTabSwitchStats) {
  RunTabSwitchingUITest();
}

}  // namespace
<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qi/signal.hpp>
#include <qi/future.hpp>
#include <qi/signalspy.hpp>
#include <qi/anyobject.hpp>
#include <qi/application.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include <qi/type/dynamicobjectbuilder.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(qi::Atomic<int>* r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); ++*r;
  }
  void func2(qi::Atomic<int>* r, int, int) { ++*r; }
};
void foo(qi::Atomic<int>* r, int, int)     { ++*r; }
void foo2(qi::Atomic<int>* r, char, char)  { ++*r; }
void foo3(qi::Atomic<int>* r, Foo *)       { ++*r; }
void foolast(int, qi::Promise<void> prom, qi::Atomic<int>* r) { prom.setValue(0); ++*r; }

TEST(TestSignal, TestCompilation)
{
  qi::Atomic<int>        res{0};
  qi::Signal<int> s;
  Foo*                   f = (Foo*)1;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::AnyFunction::from(&Foo::func, f));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);

  while (res.load() != 6)
    qi::os::msleep(10);

  ASSERT_EQ(6, res.load());
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<boost::shared_ptr<int> > sig;
  sig.connect(qi::AnyFunction::from(&write42)).setCallType(qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  qi::Atomic<int> r{0};
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<qi::Atomic<int>*, int> sig;
  sig.connect(&Foo::func1, boost::weak_ptr<Foo>(foo), _1, _2).setCallType(qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
}

void waitFuture(qi::Atomic<int>& cnt, qi::Promise<void> start, qi::Future<void> f)
{
  if (++cnt == 2)
    start.setValue(0);
  f.wait();

  // force disconnection, may trigger a segfault
  throw qi::PointerLockException();
}

TEST(TestSignal, NonBlockingDestroy)
{
  // disconnect is blocking, but signal destruction should not be

  qi::Promise<void> start;
  qi::Promise<void> finish;
  qi::Atomic<int> cnt{0};

  {
    qi::Signal<void> sig;
    sig.connect(boost::bind(waitFuture, boost::ref(cnt), start, finish.future()));

    sig();
    sig();

    start.future().wait();
    // now that the callback is running, destroy the signal
  }

  // all went well, unblock the callback
  finish.setValue(0);
}

TEST(TestSignal, BadArity)
{
  // Test runtime detection of arity errors
  qi::Signal<> s;
  // avoid using s.connect() which will catch the problem at compile-time
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo))));
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo2))));
  EXPECT_ANY_THROW(s.connect(qi::AnyFunction::from((boost::function<void(qi::Atomic<int>*, int)>)boost::bind(&Foo::func1, (Foo*)0, _1, _2))));
}

void lol(int v, int& target)
{
  target = v;
}
TEST(TestSignal, SignalSignal)
{
  qi::SignalF<void (int)> sig1;
  qi::SignalF<void (int)> *sig2 = new  qi::SignalF<void (int)>();
  sig1.connect(*sig2);
  qi::SignalSpy spy(*sig2);
  sig1(10);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(10, spy.record(0).arg<int>(0));

  // Test autodisconnect
  delete sig2;
  sig1(20);
  ASSERT_FALSE(spy.waitUntil(2, qi::MilliSeconds(300)));
}

class SignalTest {
public:
  qi::Signal<int> sig;
  qi::Signal<int> sig2;
};

TEST(TestSignal, SignalSignal2)
{
  SignalTest st;
  qi::SignalSpy spy(st.sig2);
  st.sig.connect(st.sig2);
  qiLogDebug() << "sigptrs are " << &st.sig << " " << &st.sig2;
  st.sig(4242);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  assert(spy.recordCount() == 1u);
  EXPECT_EQ(4242, spy.lastRecord().arg<int>(0));
}

TEST(TestSignal, SignalN)
{
  qi::Signal<int> sig;
  qi::SignalSpy spy(sig);
  sig(5);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(5, spy.lastRecord().arg<int>(0));
}

class SigHolder
{
public:
  qi::Signal<> s0;
  qi::Signal<int> s1;
  qi::Signal<int, int> s2;
  void fire0() { s0();}
  void fire1(int i) { s1(i); }
  void fire2(int i, int j) { s2(i, j);}
};

QI_REGISTER_OBJECT(SigHolder, s0, s1, s2, fire0, fire1, fire2)

TEST(TestSignal, SignalNBind)
{
  int res = 0;
  boost::shared_ptr<SigHolder> so(new SigHolder);
  qi::AnyObject op = qi::AnyReference::from(so).to<qi::AnyObject>();
  qi::detail::printMetaObject(std::cerr, op.metaObject());
  op.connect("s1", (boost::function<void(int)>)boost::bind<void>(&lol, _1, boost::ref(res)));
  op.post("s1", 2);
  for (unsigned i=0; i<30 && res!=2; ++i) qi::os::msleep(10);
  ASSERT_EQ(2, res);
  so->s1(3);
  for (unsigned i=0; i<30 && res!=3; ++i) qi::os::msleep(10);
  ASSERT_EQ(3, res);
  so->s0.connect( boost::bind<void>(&lol, 42, boost::ref(res)));
  op.post("s0");
  for (unsigned i=0; i<30 && res!=42; ++i) qi::os::msleep(10);
  ASSERT_EQ(42, res);
}

void foothrow() {
  throw 42;
}

TEST(TestSignal, SignalThrow)
{
  qi::Signal<> sig;
  sig.connect(boost::bind<void>(&foothrow));
  ASSERT_NO_THROW(sig());
  qi::os::msleep(50);
}

void dynTest0(int& tgt)                     { tgt |= 1;}
void dynTest1(int& tgt, int)                { tgt |= 2;}
void dynTest2(int& tgt, int, int)           { tgt |= 4;}
void dynTest3(int& tgt, int, std::string)   { tgt |= 8;}
void dynTestN(int& tgt, const qi::AnyArguments& a)   { tgt |= 32;}
qi::AnyReference dynTestN2(int& tgt, const std::vector<qi::AnyReference>& a)   { tgt |= 16; return qi::AnyReference();}

TEST(TestSignal, Dynamic)
{
  qi::SignalBase s(qi::Signature("m"));
  int trig = 0;
  s.setCallType(qi::MetaCallType_Direct);
  s.connect((boost::function<void()>) boost::bind(&dynTest0, boost::ref(trig)));
  s.connect((boost::function<void(int)>) boost::bind(&dynTest1, boost::ref(trig), _1));
  s.connect((boost::function<void(int, int)>) boost::bind(&dynTest2, boost::ref(trig), _1, _2));
  s.connect((boost::function<void(int, std::string)>) boost::bind(&dynTest3, boost::ref(trig), _1, _2));
  s.connect(qi::AnyFunction::fromDynamicFunction(boost::bind(&dynTestN2, boost::ref(trig), _1)));
  s.connect((boost::function<void(const qi::AnyArguments&)>)(boost::bind(&dynTestN, boost::ref(trig), _1)));
  int a, b;
  std::string c;
  qi::GenericFunctionParameters params;
  s.trigger(params);
  EXPECT_EQ(49, trig);
  params.push_back(qi::AnyReference::from(a));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(50, trig);
  params.push_back(qi::AnyReference::from(b));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(52, trig);
  params[1] = qi::AnyReference::from(c);
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(56, trig);
}

void onSubs(std::atomic<bool>& var, bool subs)
{
  var = subs;
}

void callback(int i)
{}

TEST(TestSignal, OnSubscriber)
{
  std::atomic<bool> subscribers(false);

  qi::Signal<int> sig(boost::bind(onSubs, boost::ref(subscribers), _1));
  ASSERT_FALSE(subscribers);
  qi::SignalLink l = sig.connect(&callback);
  ASSERT_TRUE(subscribers);
  ASSERT_TRUE(sig.disconnect(l));
  ASSERT_FALSE(subscribers);
}

void store2(qi::Promise<int> variable1, qi::Promise<int> variable2, int value1, int value2)
{
  variable1.setValue(value1);
  variable2.setValue(value2);
}

TEST(TestSignal, SignalToSignalWithExtraArgument)
{
  qi::Promise<int> target1, target2;
  qi::Signal<int> signal1;
  qi::Signal<int, int> signal2;
  signal1.connect(boost::bind(boost::ref(signal2), _1, 42));
  signal2.connect(store2, target1, target2, _1, _2);
  signal1(12);
  EXPECT_EQ(12, target1.future().value());
  EXPECT_EQ(42, target2.future().value());
}

TEST(TestSignal, SignalSubscriberDoesNotUnsubscribeAtDestruction)
{
  int count = 0;
  qi::Signal<void> signal;
  auto subscriber = signal.connect([&]{ ++count; })
      .setCallType(qi::MetaCallType_Direct)
      .shared_from_this();
  signal();
  ASSERT_EQ(1, count);

  subscriber.reset();
  signal();
  ASSERT_EQ(2, count);
}

// ===========================================================
// Signal Spy
// -----------------------------------------------------------
TEST(TestSignalSpy, Counter)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp.getCounter(), 2u);

  qi::DynamicObjectBuilder ob;
  ob.advertiseSignal("signal", &sig);
  qi::AnyObject obj(ob.object());
  qi::SignalSpy sp2(obj, "signal");
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp2.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp2.getCounter(), 2u);
}

TEST(TestSignalSpy, Async)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  qi::async(boost::bind(boost::ref(sig), 1));
  qi::async(boost::bind(boost::ref(sig), 1));
  ASSERT_TRUE(sp.waitUntil(2, qi::Seconds(1)));
  ASSERT_EQ(sp.recordCount(), 2u);
}

TEST(TestSignalSpy, StoringTypedValueRecords)
{
  const std::vector<int> ints{ 1, 42, 13, 2016 };
  const std::vector<std::string> strings{ "poil", "slip", "banane", "pancréas" };
  qi::Signal<int, std::string> signal;
  qi::SignalSpy spy(signal);

  signal(ints[0], strings[0]);
  ASSERT_EQ(1u, spy.recordCount());
  auto record = spy.record(0);
  ASSERT_EQ(ints[0], record.arg<int>(0));
  ASSERT_EQ(strings[0], record.arg<std::string>(1));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    signal(ints[i], strings[i]);
  }
  spy.waitUntil(ints.size(), qi::MilliSeconds(300));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    record = spy.record(i);
    EXPECT_EQ(ints[i], record.arg<int>(0));
    EXPECT_EQ(strings[i], record.arg<std::string>(1));
  }

  auto records = spy.allRecords();
  ASSERT_EQ(ints.size(), records.size());
  for(auto i = 0u; i < records.size(); ++i)
  {
    EXPECT_EQ(ints[i], records[i].arg<int>(0));
    EXPECT_EQ(strings[i], records[i].arg<std::string>(1));
  }
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  qi::log::addFilter("*", qi::LogLevel_Debug);
  return RUN_ALL_TESTS();
}
<commit_msg>Fixed warning: we were using deprecated SignalSpy functions in tests.<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qi/signal.hpp>
#include <qi/future.hpp>
#include <qi/signalspy.hpp>
#include <qi/anyobject.hpp>
#include <qi/application.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include <qi/type/dynamicobjectbuilder.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(qi::Atomic<int>* r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); ++*r;
  }
  void func2(qi::Atomic<int>* r, int, int) { ++*r; }
};
void foo(qi::Atomic<int>* r, int, int)     { ++*r; }
void foo2(qi::Atomic<int>* r, char, char)  { ++*r; }
void foo3(qi::Atomic<int>* r, Foo *)       { ++*r; }
void foolast(int, qi::Promise<void> prom, qi::Atomic<int>* r) { prom.setValue(0); ++*r; }

TEST(TestSignal, TestCompilation)
{
  qi::Atomic<int>        res{0};
  qi::Signal<int> s;
  Foo*                   f = (Foo*)1;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::AnyFunction::from(&Foo::func, f));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);

  while (res.load() != 6)
    qi::os::msleep(10);

  ASSERT_EQ(6, res.load());
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<boost::shared_ptr<int> > sig;
  sig.connect(qi::AnyFunction::from(&write42)).setCallType(qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  qi::Atomic<int> r{0};
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<qi::Atomic<int>*, int> sig;
  sig.connect(&Foo::func1, boost::weak_ptr<Foo>(foo), _1, _2).setCallType(qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
}

void waitFuture(qi::Atomic<int>& cnt, qi::Promise<void> start, qi::Future<void> f)
{
  if (++cnt == 2)
    start.setValue(0);
  f.wait();

  // force disconnection, may trigger a segfault
  throw qi::PointerLockException();
}

TEST(TestSignal, NonBlockingDestroy)
{
  // disconnect is blocking, but signal destruction should not be

  qi::Promise<void> start;
  qi::Promise<void> finish;
  qi::Atomic<int> cnt{0};

  {
    qi::Signal<void> sig;
    sig.connect(boost::bind(waitFuture, boost::ref(cnt), start, finish.future()));

    sig();
    sig();

    start.future().wait();
    // now that the callback is running, destroy the signal
  }

  // all went well, unblock the callback
  finish.setValue(0);
}

TEST(TestSignal, BadArity)
{
  // Test runtime detection of arity errors
  qi::Signal<> s;
  // avoid using s.connect() which will catch the problem at compile-time
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo))));
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo2))));
  EXPECT_ANY_THROW(s.connect(qi::AnyFunction::from((boost::function<void(qi::Atomic<int>*, int)>)boost::bind(&Foo::func1, (Foo*)0, _1, _2))));
}

void lol(int v, int& target)
{
  target = v;
}
TEST(TestSignal, SignalSignal)
{
  qi::SignalF<void (int)> sig1;
  qi::SignalF<void (int)> *sig2 = new  qi::SignalF<void (int)>();
  sig1.connect(*sig2);
  qi::SignalSpy spy(*sig2);
  sig1(10);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(10, spy.record(0).arg<int>(0));

  // Test autodisconnect
  delete sig2;
  sig1(20);
  ASSERT_FALSE(spy.waitUntil(2, qi::MilliSeconds(300)));
}

class SignalTest {
public:
  qi::Signal<int> sig;
  qi::Signal<int> sig2;
};

TEST(TestSignal, SignalSignal2)
{
  SignalTest st;
  qi::SignalSpy spy(st.sig2);
  st.sig.connect(st.sig2);
  qiLogDebug() << "sigptrs are " << &st.sig << " " << &st.sig2;
  st.sig(4242);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  assert(spy.recordCount() == 1u);
  EXPECT_EQ(4242, spy.lastRecord().arg<int>(0));
}

TEST(TestSignal, SignalN)
{
  qi::Signal<int> sig;
  qi::SignalSpy spy(sig);
  sig(5);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(5, spy.lastRecord().arg<int>(0));
}

class SigHolder
{
public:
  qi::Signal<> s0;
  qi::Signal<int> s1;
  qi::Signal<int, int> s2;
  void fire0() { s0();}
  void fire1(int i) { s1(i); }
  void fire2(int i, int j) { s2(i, j);}
};

QI_REGISTER_OBJECT(SigHolder, s0, s1, s2, fire0, fire1, fire2)

TEST(TestSignal, SignalNBind)
{
  int res = 0;
  boost::shared_ptr<SigHolder> so(new SigHolder);
  qi::AnyObject op = qi::AnyReference::from(so).to<qi::AnyObject>();
  qi::detail::printMetaObject(std::cerr, op.metaObject());
  op.connect("s1", (boost::function<void(int)>)boost::bind<void>(&lol, _1, boost::ref(res)));
  op.post("s1", 2);
  for (unsigned i=0; i<30 && res!=2; ++i) qi::os::msleep(10);
  ASSERT_EQ(2, res);
  so->s1(3);
  for (unsigned i=0; i<30 && res!=3; ++i) qi::os::msleep(10);
  ASSERT_EQ(3, res);
  so->s0.connect( boost::bind<void>(&lol, 42, boost::ref(res)));
  op.post("s0");
  for (unsigned i=0; i<30 && res!=42; ++i) qi::os::msleep(10);
  ASSERT_EQ(42, res);
}

void foothrow() {
  throw 42;
}

TEST(TestSignal, SignalThrow)
{
  qi::Signal<> sig;
  sig.connect(boost::bind<void>(&foothrow));
  ASSERT_NO_THROW(sig());
  qi::os::msleep(50);
}

void dynTest0(int& tgt)                     { tgt |= 1;}
void dynTest1(int& tgt, int)                { tgt |= 2;}
void dynTest2(int& tgt, int, int)           { tgt |= 4;}
void dynTest3(int& tgt, int, std::string)   { tgt |= 8;}
void dynTestN(int& tgt, const qi::AnyArguments& a)   { tgt |= 32;}
qi::AnyReference dynTestN2(int& tgt, const std::vector<qi::AnyReference>& a)   { tgt |= 16; return qi::AnyReference();}

TEST(TestSignal, Dynamic)
{
  qi::SignalBase s(qi::Signature("m"));
  int trig = 0;
  s.setCallType(qi::MetaCallType_Direct);
  s.connect((boost::function<void()>) boost::bind(&dynTest0, boost::ref(trig)));
  s.connect((boost::function<void(int)>) boost::bind(&dynTest1, boost::ref(trig), _1));
  s.connect((boost::function<void(int, int)>) boost::bind(&dynTest2, boost::ref(trig), _1, _2));
  s.connect((boost::function<void(int, std::string)>) boost::bind(&dynTest3, boost::ref(trig), _1, _2));
  s.connect(qi::AnyFunction::fromDynamicFunction(boost::bind(&dynTestN2, boost::ref(trig), _1)));
  s.connect((boost::function<void(const qi::AnyArguments&)>)(boost::bind(&dynTestN, boost::ref(trig), _1)));
  int a, b;
  std::string c;
  qi::GenericFunctionParameters params;
  s.trigger(params);
  EXPECT_EQ(49, trig);
  params.push_back(qi::AnyReference::from(a));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(50, trig);
  params.push_back(qi::AnyReference::from(b));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(52, trig);
  params[1] = qi::AnyReference::from(c);
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(56, trig);
}

void onSubs(std::atomic<bool>& var, bool subs)
{
  var = subs;
}

void callback(int i)
{}

TEST(TestSignal, OnSubscriber)
{
  std::atomic<bool> subscribers(false);

  qi::Signal<int> sig(boost::bind(onSubs, boost::ref(subscribers), _1));
  ASSERT_FALSE(subscribers);
  qi::SignalLink l = sig.connect(&callback);
  ASSERT_TRUE(subscribers);
  ASSERT_TRUE(sig.disconnect(l));
  ASSERT_FALSE(subscribers);
}

void store2(qi::Promise<int> variable1, qi::Promise<int> variable2, int value1, int value2)
{
  variable1.setValue(value1);
  variable2.setValue(value2);
}

TEST(TestSignal, SignalToSignalWithExtraArgument)
{
  qi::Promise<int> target1, target2;
  qi::Signal<int> signal1;
  qi::Signal<int, int> signal2;
  signal1.connect(boost::bind(boost::ref(signal2), _1, 42));
  signal2.connect(store2, target1, target2, _1, _2);
  signal1(12);
  EXPECT_EQ(12, target1.future().value());
  EXPECT_EQ(42, target2.future().value());
}

TEST(TestSignal, SignalSubscriberDoesNotUnsubscribeAtDestruction)
{
  int count = 0;
  qi::Signal<void> signal;
  auto subscriber = signal.connect([&]{ ++count; })
      .setCallType(qi::MetaCallType_Direct)
      .shared_from_this();
  signal();
  ASSERT_EQ(1, count);

  subscriber.reset();
  signal();
  ASSERT_EQ(2, count);
}

// ===========================================================
// Signal Spy
// -----------------------------------------------------------
TEST(TestSignalSpy, Counter)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp.recordCount(), 2u);

  qi::DynamicObjectBuilder ob;
  ob.advertiseSignal("signal", &sig);
  qi::AnyObject obj(ob.object());
  qi::SignalSpy sp2(obj, "signal");
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp2.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp2.recordCount(), 2u);
}

TEST(TestSignalSpy, Async)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  qi::async(boost::bind(boost::ref(sig), 1));
  qi::async(boost::bind(boost::ref(sig), 1));
  ASSERT_TRUE(sp.waitUntil(2, qi::Seconds(1)));
  ASSERT_EQ(sp.recordCount(), 2u);
}

TEST(TestSignalSpy, StoringTypedValueRecords)
{
  const std::vector<int> ints{ 1, 42, 13, 2016 };
  const std::vector<std::string> strings{ "poil", "slip", "banane", "pancréas" };
  qi::Signal<int, std::string> signal;
  qi::SignalSpy spy(signal);

  signal(ints[0], strings[0]);
  ASSERT_EQ(1u, spy.recordCount());
  auto record = spy.record(0);
  ASSERT_EQ(ints[0], record.arg<int>(0));
  ASSERT_EQ(strings[0], record.arg<std::string>(1));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    signal(ints[i], strings[i]);
  }
  spy.waitUntil(ints.size(), qi::MilliSeconds(300));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    record = spy.record(i);
    EXPECT_EQ(ints[i], record.arg<int>(0));
    EXPECT_EQ(strings[i], record.arg<std::string>(1));
  }

  auto records = spy.allRecords();
  ASSERT_EQ(ints.size(), records.size());
  for(auto i = 0u; i < records.size(); ++i)
  {
    EXPECT_EQ(ints[i], records[i].arg<int>(0));
    EXPECT_EQ(strings[i], records[i].arg<std::string>(1));
  }
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  qi::log::addFilter("*", qi::LogLevel_Debug);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xeroot.cxx,v $
 *
 *  $Revision: 1.18 $
 *
 *  last change: $Author: obo $ $Date: 2006-03-22 12:01:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_XEROOT_HXX
#include "xeroot.hxx"
#endif

#ifndef _SVSTOR_HXX
#include <so3/svstor.hxx>
#endif
#ifndef _SFXDOCFILE_HXX
#include <sfx2/docfile.hxx>
#endif
#ifndef INCLUDED_SVTOOLS_SAVEOPT_HXX
#include <svtools/saveopt.hxx>
#endif

#ifndef SC_XLTRACER_HXX
#include "xltracer.hxx"
#endif
#ifndef SC_XEHELPER_HXX
#include "xehelper.hxx"
#endif
#ifndef SC_XEFORMULA_HXX
#include "xeformula.hxx"
#endif
#ifndef SC_XELINK_HXX
#include "xelink.hxx"
#endif
#ifndef SC_XENAME_HXX
#include "xename.hxx"
#endif
#ifndef SC_XESTYLE_HXX
#include "xestyle.hxx"
#endif
#ifndef SC_XECONTENT_HXX
#include "xecontent.hxx"
#endif
#ifndef SC_XEPIVOT_HXX
#include "xepivot.hxx"
#endif

// for filter manager
#include "excrecds.hxx"

// Global data ================================================================

XclExpRootData::XclExpRootData( XclBiff eBiff, SfxMedium& rMedium,
        SotStorageRef xRootStrg, ScDocument& rDoc, CharSet eCharSet ) :
    XclRootData( eBiff, rMedium, xRootStrg, rDoc, eCharSet, true )
{
    SvtSaveOptions aSaveOpt;
    mbRelUrl = mrMedium.IsRemote() ? aSaveOpt.IsSaveRelINet() : aSaveOpt.IsSaveRelFSys();
}

XclExpRootData::~XclExpRootData()
{
}

// ----------------------------------------------------------------------------

XclExpRoot::XclExpRoot( XclExpRootData& rExpRootData ) :
    XclRoot( rExpRootData ),
    mrExpData( rExpRootData )
{
}

XclExpTabInfo& XclExpRoot::GetTabInfo() const
{
    DBG_ASSERT( mrExpData.mxTabInfo.is(), "XclExpRoot::GetTabInfo - missing object (wrong BIFF?)" );
    return *mrExpData.mxTabInfo;
}

XclExpAddressConverter& XclExpRoot::GetAddressConverter() const
{
    DBG_ASSERT( mrExpData.mxAddrConv.is(), "XclExpRoot::GetAddressConverter - missing object (wrong BIFF?)" );
    return *mrExpData.mxAddrConv;
}

XclExpFormulaCompiler& XclExpRoot::GetFormulaCompiler() const
{
    DBG_ASSERT( mrExpData.mxFmlaComp.is(), "XclExpRoot::GetFormulaCompiler - missing object (wrong BIFF?)" );
    return *mrExpData.mxFmlaComp;
}

XclExpProgressBar& XclExpRoot::GetProgressBar() const
{
    DBG_ASSERT( mrExpData.mxProgress.is(), "XclExpRoot::GetProgressBar - missing object (wrong BIFF?)" );
    return *mrExpData.mxProgress;
}

XclExpSst& XclExpRoot::GetSst() const
{
    DBG_ASSERT( mrExpData.mxSst.is(), "XclExpRoot::GetSst - missing object (wrong BIFF?)" );
    return *mrExpData.mxSst;
}

XclExpPalette& XclExpRoot::GetPalette() const
{
    DBG_ASSERT( mrExpData.mxPalette.is(), "XclExpRoot::GetPalette - missing object (wrong BIFF?)" );
    return *mrExpData.mxPalette;
}

XclExpFontBuffer& XclExpRoot::GetFontBuffer() const
{
    DBG_ASSERT( mrExpData.mxFontBfr.is(), "XclExpRoot::GetFontBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxFontBfr;
}

XclExpNumFmtBuffer& XclExpRoot::GetNumFmtBuffer() const
{
    DBG_ASSERT( mrExpData.mxNumFmtBfr.is(), "XclExpRoot::GetNumFmtBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxNumFmtBfr;
}

XclExpXFBuffer& XclExpRoot::GetXFBuffer() const
{
    DBG_ASSERT( mrExpData.mxXFBfr.is(), "XclExpRoot::GetXFBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxXFBfr;
}

XclExpLinkManager& XclExpRoot::GetGlobalLinkManager() const
{
    DBG_ASSERT( mrExpData.mxGlobLinkMgr.is(), "XclExpRoot::GetGlobalLinkManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxGlobLinkMgr;
}

XclExpLinkManager& XclExpRoot::GetLocalLinkManager() const
{
    DBG_ASSERT( GetLocalLinkMgrRef().is(), "XclExpRoot::GetLocalLinkManager - missing object (wrong BIFF?)" );
    return *GetLocalLinkMgrRef();
}

XclExpNameManager& XclExpRoot::GetNameManager() const
{
    DBG_ASSERT( mrExpData.mxNameMgr.is(), "XclExpRoot::GetNameManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxNameMgr;
}

XclExpFilterManager& XclExpRoot::GetFilterManager() const
{
    DBG_ASSERT( mrExpData.mxFilterMgr.is(), "XclExpRoot::GetFilterManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxFilterMgr;
}

XclExpPivotTableManager& XclExpRoot::GetPivotTableManager() const
{
    DBG_ASSERT( mrExpData.mxPTableMgr.is(), "XclExpRoot::GetPivotTableManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxPTableMgr;
}

void XclExpRoot::InitializeConvert()
{
    mrExpData.mxTabInfo.reset( new XclExpTabInfo( GetRoot() ) );
    mrExpData.mxAddrConv.reset( new XclExpAddressConverter( GetRoot() ) );
    mrExpData.mxFmlaComp.reset( new XclExpFormulaCompiler( GetRoot() ) );
    mrExpData.mxProgress.reset( new XclExpProgressBar( GetRoot() ) );

    GetProgressBar().Initialize();
}

void XclExpRoot::InitializeGlobals()
{
    SetCurrScTab( SCTAB_GLOBAL );

    if( GetBiff() >= EXC_BIFF5 )
    {
        mrExpData.mxPalette.reset( new XclExpPalette( GetRoot() ) );
        mrExpData.mxFontBfr.reset( new XclExpFontBuffer( GetRoot() ) );
        mrExpData.mxNumFmtBfr.reset( new XclExpNumFmtBuffer( GetRoot() ) );
        mrExpData.mxXFBfr.reset( new XclExpXFBuffer( GetRoot() ) );
        mrExpData.mxGlobLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
        mrExpData.mxNameMgr.reset( new XclExpNameManager( GetRoot() ) );
    }

    if( GetBiff() == EXC_BIFF8 )
    {
        mrExpData.mxSst.reset( new XclExpSst );
        mrExpData.mxFilterMgr.reset( new XclExpFilterManager( GetRoot() ) );
        mrExpData.mxPTableMgr.reset( new XclExpPivotTableManager( GetRoot() ) );
        // BIFF8: only one link manager for all sheets
        mrExpData.mxLocLinkMgr = mrExpData.mxGlobLinkMgr;
    }

    GetXFBuffer().Initialize();
    GetNameManager().Initialize();
}

void XclExpRoot::InitializeTable( SCTAB nScTab )
{
    SetCurrScTab( nScTab );
    if( GetBiff() == EXC_BIFF5 )
    {
        // local link manager per sheet
        mrExpData.mxLocLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
    }
}

void XclExpRoot::InitializeSave()
{
    GetPalette().Finalize();
    GetXFBuffer().Finalize();
}

XclExpRecordRef XclExpRoot::CreateRecord( sal_uInt16 nRecId ) const
{
    XclExpRecordRef xRec;
    switch( nRecId )
    {
        case EXC_ID_PALETTE:        xRec = mrExpData.mxPalette;     break;
        case EXC_ID_FONT:           xRec = mrExpData.mxFontBfr;     break;
        case EXC_ID_FORMAT:         xRec = mrExpData.mxNumFmtBfr;   break;
        case EXC_ID_XF:             xRec = mrExpData.mxXFBfr;       break;
        case EXC_ID_SST:            xRec = mrExpData.mxSst;         break;
        case EXC_ID_EXTERNSHEET:    xRec = GetLocalLinkMgrRef();    break;
        case EXC_ID_NAME:           xRec = mrExpData.mxNameMgr;     break;
    }
    DBG_ASSERT( xRec.is(), "XclExpRoot::CreateRecord - unknown record ID or missing object" );
    return xRec;
}

XclExpRootData::XclExpLinkMgrRef XclExpRoot::GetLocalLinkMgrRef() const
{
    return IsInGlobals() ? mrExpData.mxGlobLinkMgr : mrExpData.mxLocLinkMgr;
}

// ============================================================================

<commit_msg>INTEGRATION: CWS calc36 (1.18.18); FILE MERGED 2006/04/06 12:16:35 dr 1.18.18.1: #i62752# #i63502# #i63591# moved changes from CWS dr47<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xeroot.cxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: rt $ $Date: 2006-05-05 09:37:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_XEROOT_HXX
#include "xeroot.hxx"
#endif

#ifndef _SVSTOR_HXX
#include <so3/svstor.hxx>
#endif
#ifndef _SFXDOCFILE_HXX
#include <sfx2/docfile.hxx>
#endif
#ifndef INCLUDED_SVTOOLS_SAVEOPT_HXX
#include <svtools/saveopt.hxx>
#endif

#ifndef SC_XLTRACER_HXX
#include "xltracer.hxx"
#endif
#ifndef SC_XEHELPER_HXX
#include "xehelper.hxx"
#endif
#ifndef SC_XEFORMULA_HXX
#include "xeformula.hxx"
#endif
#ifndef SC_XELINK_HXX
#include "xelink.hxx"
#endif
#ifndef SC_XENAME_HXX
#include "xename.hxx"
#endif
#ifndef SC_XESTYLE_HXX
#include "xestyle.hxx"
#endif
#ifndef SC_XECONTENT_HXX
#include "xecontent.hxx"
#endif
#ifndef SC_XEPIVOT_HXX
#include "xepivot.hxx"
#endif

// for filter manager
#include "excrecds.hxx"

// Global data ================================================================

XclExpRootData::XclExpRootData( XclBiff eBiff, SfxMedium& rMedium,
        SotStorageRef xRootStrg, ScDocument& rDoc, CharSet eCharSet ) :
    XclRootData( eBiff, rMedium, xRootStrg, rDoc, eCharSet, true )
{
    SvtSaveOptions aSaveOpt;
    mbRelUrl = mrMedium.IsRemote() ? aSaveOpt.IsSaveRelINet() : aSaveOpt.IsSaveRelFSys();
}

XclExpRootData::~XclExpRootData()
{
}

// ----------------------------------------------------------------------------

XclExpRoot::XclExpRoot( XclExpRootData& rExpRootData ) :
    XclRoot( rExpRootData ),
    mrExpData( rExpRootData )
{
}

XclExpTabInfo& XclExpRoot::GetTabInfo() const
{
    DBG_ASSERT( mrExpData.mxTabInfo.is(), "XclExpRoot::GetTabInfo - missing object (wrong BIFF?)" );
    return *mrExpData.mxTabInfo;
}

XclExpAddressConverter& XclExpRoot::GetAddressConverter() const
{
    DBG_ASSERT( mrExpData.mxAddrConv.is(), "XclExpRoot::GetAddressConverter - missing object (wrong BIFF?)" );
    return *mrExpData.mxAddrConv;
}

XclExpFormulaCompiler& XclExpRoot::GetFormulaCompiler() const
{
    DBG_ASSERT( mrExpData.mxFmlaComp.is(), "XclExpRoot::GetFormulaCompiler - missing object (wrong BIFF?)" );
    return *mrExpData.mxFmlaComp;
}

XclExpProgressBar& XclExpRoot::GetProgressBar() const
{
    DBG_ASSERT( mrExpData.mxProgress.is(), "XclExpRoot::GetProgressBar - missing object (wrong BIFF?)" );
    return *mrExpData.mxProgress;
}

XclExpSst& XclExpRoot::GetSst() const
{
    DBG_ASSERT( mrExpData.mxSst.is(), "XclExpRoot::GetSst - missing object (wrong BIFF?)" );
    return *mrExpData.mxSst;
}

XclExpPalette& XclExpRoot::GetPalette() const
{
    DBG_ASSERT( mrExpData.mxPalette.is(), "XclExpRoot::GetPalette - missing object (wrong BIFF?)" );
    return *mrExpData.mxPalette;
}

XclExpFontBuffer& XclExpRoot::GetFontBuffer() const
{
    DBG_ASSERT( mrExpData.mxFontBfr.is(), "XclExpRoot::GetFontBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxFontBfr;
}

XclExpNumFmtBuffer& XclExpRoot::GetNumFmtBuffer() const
{
    DBG_ASSERT( mrExpData.mxNumFmtBfr.is(), "XclExpRoot::GetNumFmtBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxNumFmtBfr;
}

XclExpXFBuffer& XclExpRoot::GetXFBuffer() const
{
    DBG_ASSERT( mrExpData.mxXFBfr.is(), "XclExpRoot::GetXFBuffer - missing object (wrong BIFF?)" );
    return *mrExpData.mxXFBfr;
}

XclExpLinkManager& XclExpRoot::GetGlobalLinkManager() const
{
    DBG_ASSERT( mrExpData.mxGlobLinkMgr.is(), "XclExpRoot::GetGlobalLinkManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxGlobLinkMgr;
}

XclExpLinkManager& XclExpRoot::GetLocalLinkManager() const
{
    DBG_ASSERT( GetLocalLinkMgrRef().is(), "XclExpRoot::GetLocalLinkManager - missing object (wrong BIFF?)" );
    return *GetLocalLinkMgrRef();
}

XclExpNameManager& XclExpRoot::GetNameManager() const
{
    DBG_ASSERT( mrExpData.mxNameMgr.is(), "XclExpRoot::GetNameManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxNameMgr;
}

XclExpFilterManager& XclExpRoot::GetFilterManager() const
{
    DBG_ASSERT( mrExpData.mxFilterMgr.is(), "XclExpRoot::GetFilterManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxFilterMgr;
}

XclExpPivotTableManager& XclExpRoot::GetPivotTableManager() const
{
    DBG_ASSERT( mrExpData.mxPTableMgr.is(), "XclExpRoot::GetPivotTableManager - missing object (wrong BIFF?)" );
    return *mrExpData.mxPTableMgr;
}

void XclExpRoot::InitializeConvert()
{
    mrExpData.mxTabInfo.reset( new XclExpTabInfo( GetRoot() ) );
    mrExpData.mxAddrConv.reset( new XclExpAddressConverter( GetRoot() ) );
    mrExpData.mxFmlaComp.reset( new XclExpFormulaCompiler( GetRoot() ) );
    mrExpData.mxProgress.reset( new XclExpProgressBar( GetRoot() ) );

    GetProgressBar().Initialize();
}

void XclExpRoot::InitializeGlobals()
{
    SetCurrScTab( SCTAB_GLOBAL );

    if( GetBiff() >= EXC_BIFF5 )
    {
        mrExpData.mxPalette.reset( new XclExpPalette( GetRoot() ) );
        mrExpData.mxFontBfr.reset( new XclExpFontBuffer( GetRoot() ) );
        mrExpData.mxNumFmtBfr.reset( new XclExpNumFmtBuffer( GetRoot() ) );
        mrExpData.mxXFBfr.reset( new XclExpXFBuffer( GetRoot() ) );
        mrExpData.mxGlobLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
        mrExpData.mxNameMgr.reset( new XclExpNameManager( GetRoot() ) );
    }

    if( GetBiff() == EXC_BIFF8 )
    {
        mrExpData.mxSst.reset( new XclExpSst );
        mrExpData.mxFilterMgr.reset( new XclExpFilterManager( GetRoot() ) );
        mrExpData.mxPTableMgr.reset( new XclExpPivotTableManager( GetRoot() ) );
        // BIFF8: only one link manager for all sheets
        mrExpData.mxLocLinkMgr = mrExpData.mxGlobLinkMgr;
    }

    GetXFBuffer().Initialize();
    GetNameManager().Initialize();
}

void XclExpRoot::InitializeTable( SCTAB nScTab )
{
    SetCurrScTab( nScTab );
    if( GetBiff() == EXC_BIFF5 )
    {
        // local link manager per sheet
        mrExpData.mxLocLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
    }
}

void XclExpRoot::InitializeSave()
{
    GetPalette().Finalize();
    GetXFBuffer().Finalize();
}

XclExpRecordRef XclExpRoot::CreateRecord( sal_uInt16 nRecId ) const
{
    XclExpRecordRef xRec;
    switch( nRecId )
    {
        case EXC_ID_PALETTE:        xRec = mrExpData.mxPalette;     break;
        case EXC_ID_FONTLIST:       xRec = mrExpData.mxFontBfr;     break;
        case EXC_ID_FORMATLIST:     xRec = mrExpData.mxNumFmtBfr;   break;
        case EXC_ID_XFLIST:         xRec = mrExpData.mxXFBfr;       break;
        case EXC_ID_SST:            xRec = mrExpData.mxSst;         break;
        case EXC_ID_EXTERNSHEET:    xRec = GetLocalLinkMgrRef();    break;
        case EXC_ID_NAME:           xRec = mrExpData.mxNameMgr;     break;
    }
    DBG_ASSERT( xRec.is(), "XclExpRoot::CreateRecord - unknown record ID or missing object" );
    return xRec;
}

XclExpRootData::XclExpLinkMgrRef XclExpRoot::GetLocalLinkMgrRef() const
{
    return IsInGlobals() ? mrExpData.mxGlobLinkMgr : mrExpData.mxLocLinkMgr;
}

// ============================================================================

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: xiname.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2005-01-14 12:05:56 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_XINAME_HXX
#include "xiname.hxx"
#endif

#ifndef SC_RANGENAM_HXX
#include "rangenam.hxx"
#endif

#ifndef SC_XISTREAM_HXX
#include "xistream.hxx"
#endif

// for formula compiler
#include "excform.hxx"
// for filter manager
#include "excimp8.hxx"

// ============================================================================
// *** Helper classes ***
// ============================================================================

// ============================================================================
// *** Implementation ***
// ============================================================================

XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nScIndex ) :
    XclImpRoot( rStrm.GetRoot() ),
    mpScData( 0 ),
    mcBuiltIn( EXC_BUILTIN_UNKNOWN ),
    mnScTab( SCTAB_MAX ),
    mbVBName( false )
{
    ExcelToSc& rFmlaConv = GetFmlaConverter();
    ScRangeName& rRangeNames = GetNamedRanges();

    // 1) *** read data from stream *** ---------------------------------------

    sal_uInt16 nFlags = 0, nFmlaSize, nExtSheet = EXC_NAME_GLOBAL;
    sal_uInt8 nNameLen, nShortCut;

    switch( GetBiff() )
    {
        case xlBiff2:
        {
            sal_uInt8 nFlagsBiff2;
            rStrm >> nFlagsBiff2;
            rStrm.Ignore( 1 );
            rStrm >> nShortCut >> nNameLen;
            nFmlaSize = rStrm.ReaduInt8();
            ::set_flag( nFlags, EXC_NAME_FUNC, ::get_flag( nFlagsBiff2, EXC_NAME2_FUNC ) );
        }
        break;

        case xlBiff3:
        case xlBiff4:
        {
            rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize;
        }
        break;

        case xlBiff5:
        case xlBiff7:
        case xlBiff8:
        {
            rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize;
            rStrm.Ignore( 2 );
            rStrm >> nExtSheet;
            rStrm.Ignore( 4 );
        }
        break;

        default: DBG_ERROR_BIFF();
    }

    if( GetBiff() < xlBiff8 )
        maXclName = rStrm.ReadRawByteString( nNameLen );
    else
        maXclName = rStrm.ReadUniString( nNameLen );

    // 2) *** convert sheet index and name *** --------------------------------

    // Visual Basic procedure
    mbVBName = ::get_flag( nFlags, EXC_NAME_VB );

    // get built-in name, or convert characters invalid in Calc
    bool bBuiltIn = ::get_flag( nFlags, EXC_NAME_BUILTIN );

    // special case for BIFF5 filter range - name appears as plain text without built-in flag
    if( ((GetBiff() == xlBiff5) || (GetBiff() == xlBiff7)) &&
        (maXclName == XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE )) )
    {
        bBuiltIn = true;
        maXclName.Assign( EXC_BUILTIN_FILTERDATABASE );
    }

    // convert Excel name to Calc name
    if( mbVBName )
    {
        // VB macro name
        maScName = maXclName;
    }
    else if( bBuiltIn )
    {
        // built-in name
        if( maXclName.Len() )
            mcBuiltIn = maXclName.GetChar( 0 );
        if( mcBuiltIn == '?' )      // NUL character is imported as '?'
            mcBuiltIn = '\0';
        maScName = XclTools::GetBuiltInDefName( mcBuiltIn );
    }
    else
    {
        // any other name
        maScName = maXclName;
        ScfTools::ConvertToScDefinedName( maScName );
    }

    // add index for local names
    if( nExtSheet != EXC_NAME_GLOBAL )
    {
        maScName.Append( '_' ).Append( String::CreateFromInt32( nExtSheet ) );
        mnScTab = static_cast< SCTAB >( nExtSheet - 1 );
    }

    // find an unused name
    String aOrigName( maScName );
    sal_Int32 nCounter = 0;
    USHORT nDummy;
    while( rRangeNames.SearchName( maScName, nDummy ) )
        maScName.Assign( aOrigName ).Append( ' ' ).Append( String::CreateFromInt32( ++nCounter ) );

    // 3) *** convert the name definition formula *** -------------------------

    rFmlaConv.Reset();
    const ScTokenArray* pTokArr = 0; // pointer to token array, owned by rFmlaConv
    RangeType nNameType = RT_NAME;

    const sal_uInt16 nUnsupported = EXC_NAME_VB | EXC_NAME_PROC | EXC_NAME_BIG;
    if( ::get_flag( nFlags, nUnsupported ) )
    {
        // special, unsupported name
        rFmlaConv.GetDummy( pTokArr );
    }
    else if( bBuiltIn )
    {
        // --- print ranges or title ranges ---
        rStrm.PushPosition();
        switch( mcBuiltIn )
        {
            case EXC_BUILTIN_PRINTAREA:
                if( rFmlaConv.Convert( GetPrintAreaBuffer(), nFmlaSize, FT_RangeName ) == ConvOK )
                    nNameType |= RT_PRINTAREA;
            break;
            case EXC_BUILTIN_PRINTTITLES:
                if( rFmlaConv.Convert( GetTitleAreaBuffer(), nFmlaSize, FT_RangeName ) == ConvOK )
                    nNameType |= RT_COLHEADER | RT_ROWHEADER;
            break;
        }
        rStrm.PopPosition();

        // --- name formula ---
        rFmlaConv.Convert( pTokArr, nFmlaSize, FT_RangeName );

        // --- auto or advanced filter ---
        if( (GetBiff() >= xlBiff8) && pTokArr && bBuiltIn )
        {
            ScRange aRange;
            if( pTokArr->IsReference( aRange ) )
            {
                switch( mcBuiltIn )
                {
                    case EXC_BUILTIN_FILTERDATABASE:
                        GetFilterManager().Insert( mpRD, aRange, maScName );
                    break;
                    case EXC_BUILTIN_CRITERIA:
                        GetFilterManager().AddAdvancedRange( aRange );
                        nNameType |= RT_CRITERIA;
                    break;
                    case EXC_BUILTIN_EXTRACT:
                        if( pTokArr->IsValidReference( aRange ) )
                            GetFilterManager().AddExtractPos( aRange );
                    break;
                }
            }
        }
    }
    else if( nFmlaSize > 0 )
    {
        // regular defined name
        rFmlaConv.Convert( pTokArr, nFmlaSize, FT_RangeName );
    }

    // 4) *** create a defined name in the Calc document *** ------------------

    if( pTokArr && (bBuiltIn || !::get_flag( nFlags, EXC_NAME_HIDDEN )) && !mbVBName )
    {
        // create the Calc name data
        ScRangeData* pData = new ScRangeData( GetDocPtr(), maScName, *pTokArr, ScAddress(), nNameType );
        pData->GuessPosition();
        pData->SetIndex( nScIndex );
        rRangeNames.Insert( pData );        // takes ownership of pData
        mpScData = pData;                   // cache for later use
    }
}

// ----------------------------------------------------------------------------

XclImpNameManager::XclImpNameManager( const XclImpRoot& rRoot ) :
    XclImpRoot( rRoot )
{
}

void XclImpNameManager::ReadName( XclImpStream& rStrm )
{
    ULONG nCount = maNameList.Count();
    if( nCount < 0xFFFF )
        maNameList.Append( new XclImpName( rStrm, static_cast< sal_uInt16 >( nCount + 1 ) ) );
}

const XclImpName* XclImpNameManager::FindName( const String& rXclName, SCTAB nScTab ) const
{
    const XclImpName* pGlobalName = 0;   // a found global name
    const XclImpName* pLocalName = 0;    // a found local name
    for( const XclImpName* pName = maNameList.First(); pName && !pLocalName; pName = maNameList.Next() )
    {
        if( pName->GetXclName() == rXclName )
        {
            if( pName->GetScTab() == nScTab )
                pLocalName = pName;
            else if( pName->IsGlobal() )
                pGlobalName = pName;
        }
    }
    return pLocalName ? pLocalName : pGlobalName;
}

const XclImpName* XclImpNameManager::GetName( sal_uInt16 nXclNameIdx ) const
{
    DBG_ASSERT( nXclNameIdx > 0, "XclImpNameManager::GetName - index must be >0" );
    return maNameList.GetObject( nXclNameIdx - 1 );
}

// ============================================================================

<commit_msg>INTEGRATION: CWS dr32 (1.2.2); FILE MERGED 2005/01/31 14:00:50 dr 1.2.2.3: #b6219324# #i23079# #i27871# #i35812# #i37725# new ScExtDocOptions, new Excel import/export of view settings 2005/01/19 15:00:11 dr 1.2.2.2: #i40570# removed/changed constants and enums 2005/01/18 16:34:33 dr 1.2.2.1: #i10000# merge errors<commit_after>/*************************************************************************
 *
 *  $RCSfile: xiname.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-02-21 13:32:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_XINAME_HXX
#include "xiname.hxx"
#endif

#ifndef SC_RANGENAM_HXX
#include "rangenam.hxx"
#endif

#ifndef SC_XISTREAM_HXX
#include "xistream.hxx"
#endif

// for formula compiler
#include "excform.hxx"
// for filter manager
#include "excimp8.hxx"

// ============================================================================
// *** Helper classes ***
// ============================================================================

// ============================================================================
// *** Implementation ***
// ============================================================================

XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nScIndex ) :
    XclImpRoot( rStrm.GetRoot() ),
    mpScData( 0 ),
    mcBuiltIn( EXC_BUILTIN_UNKNOWN ),
    mnScTab( SCTAB_MAX ),
    mbVBName( false )
{
    ExcelToSc& rFmlaConv = GetFmlaConverter();
    ScRangeName& rRangeNames = GetNamedRanges();

    // 1) *** read data from stream *** ---------------------------------------

    sal_uInt16 nFlags = 0, nFmlaSize, nExtSheet = EXC_NAME_GLOBAL;
    sal_uInt8 nNameLen, nShortCut;

    switch( GetBiff() )
    {
        case EXC_BIFF2:
        {
            sal_uInt8 nFlagsBiff2;
            rStrm >> nFlagsBiff2;
            rStrm.Ignore( 1 );
            rStrm >> nShortCut >> nNameLen;
            nFmlaSize = rStrm.ReaduInt8();
            ::set_flag( nFlags, EXC_NAME_FUNC, ::get_flag( nFlagsBiff2, EXC_NAME2_FUNC ) );
        }
        break;

        case EXC_BIFF3:
        case EXC_BIFF4:
        {
            rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize;
        }
        break;

        case EXC_BIFF5:
        case EXC_BIFF8:
        {
            rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize;
            rStrm.Ignore( 2 );
            rStrm >> nExtSheet;
            rStrm.Ignore( 4 );
        }
        break;

        default: DBG_ERROR_BIFF();
    }

    if( GetBiff() <= EXC_BIFF5 )
        maXclName = rStrm.ReadRawByteString( nNameLen );
    else
        maXclName = rStrm.ReadUniString( nNameLen );

    // 2) *** convert sheet index and name *** --------------------------------

    // Visual Basic procedure
    mbVBName = ::get_flag( nFlags, EXC_NAME_VB );

    // get built-in name, or convert characters invalid in Calc
    bool bBuiltIn = ::get_flag( nFlags, EXC_NAME_BUILTIN );

    // special case for BIFF5 filter range - name appears as plain text without built-in flag
    if( (GetBiff() == EXC_BIFF5) && (maXclName == XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE )) )
    {
        bBuiltIn = true;
        maXclName.Assign( EXC_BUILTIN_FILTERDATABASE );
    }

    // convert Excel name to Calc name
    if( mbVBName )
    {
        // VB macro name
        maScName = maXclName;
    }
    else if( bBuiltIn )
    {
        // built-in name
        if( maXclName.Len() )
            mcBuiltIn = maXclName.GetChar( 0 );
        if( mcBuiltIn == '?' )      // NUL character is imported as '?'
            mcBuiltIn = '\0';
        maScName = XclTools::GetBuiltInDefName( mcBuiltIn );
    }
    else
    {
        // any other name
        maScName = maXclName;
        ScfTools::ConvertToScDefinedName( maScName );
    }

    // add index for local names
    if( nExtSheet != EXC_NAME_GLOBAL )
    {
        maScName.Append( '_' ).Append( String::CreateFromInt32( nExtSheet ) );
        mnScTab = static_cast< SCTAB >( nExtSheet - 1 );
    }

    // find an unused name
    String aOrigName( maScName );
    sal_Int32 nCounter = 0;
    USHORT nDummy;
    while( rRangeNames.SearchName( maScName, nDummy ) )
        maScName.Assign( aOrigName ).Append( ' ' ).Append( String::CreateFromInt32( ++nCounter ) );

    // 3) *** convert the name definition formula *** -------------------------

    rFmlaConv.Reset();
    const ScTokenArray* pTokArr = 0; // pointer to token array, owned by rFmlaConv
    RangeType nNameType = RT_NAME;

    const sal_uInt16 nUnsupported = EXC_NAME_VB | EXC_NAME_PROC | EXC_NAME_BIG;
    if( ::get_flag( nFlags, nUnsupported ) )
    {
        // special, unsupported name
        rFmlaConv.GetDummy( pTokArr );
    }
    else if( bBuiltIn )
    {
        // --- print ranges or title ranges ---
        rStrm.PushPosition();
        switch( mcBuiltIn )
        {
            case EXC_BUILTIN_PRINTAREA:
                if( rFmlaConv.Convert( GetPrintAreaBuffer(), nFmlaSize, FT_RangeName ) == ConvOK )
                    nNameType |= RT_PRINTAREA;
            break;
            case EXC_BUILTIN_PRINTTITLES:
                if( rFmlaConv.Convert( GetTitleAreaBuffer(), nFmlaSize, FT_RangeName ) == ConvOK )
                    nNameType |= RT_COLHEADER | RT_ROWHEADER;
            break;
        }
        rStrm.PopPosition();

        // --- name formula ---
        rFmlaConv.Convert( pTokArr, nFmlaSize, FT_RangeName );

        // --- auto or advanced filter ---
        if( (GetBiff() == EXC_BIFF8) && pTokArr && bBuiltIn )
        {
            ScRange aRange;
            if( pTokArr->IsReference( aRange ) )
            {
                switch( mcBuiltIn )
                {
                    case EXC_BUILTIN_FILTERDATABASE:
                        GetFilterManager().Insert( &GetOldRoot(), aRange, maScName );
                    break;
                    case EXC_BUILTIN_CRITERIA:
                        GetFilterManager().AddAdvancedRange( aRange );
                        nNameType |= RT_CRITERIA;
                    break;
                    case EXC_BUILTIN_EXTRACT:
                        if( pTokArr->IsValidReference( aRange ) )
                            GetFilterManager().AddExtractPos( aRange );
                    break;
                }
            }
        }
    }
    else if( nFmlaSize > 0 )
    {
        // regular defined name
        rFmlaConv.Convert( pTokArr, nFmlaSize, FT_RangeName );
    }

    // 4) *** create a defined name in the Calc document *** ------------------

    if( pTokArr && (bBuiltIn || !::get_flag( nFlags, EXC_NAME_HIDDEN )) && !mbVBName )
    {
        // create the Calc name data
        ScRangeData* pData = new ScRangeData( GetDocPtr(), maScName, *pTokArr, ScAddress(), nNameType );
        pData->GuessPosition();
        pData->SetIndex( nScIndex );
        rRangeNames.Insert( pData );        // takes ownership of pData
        mpScData = pData;                   // cache for later use
    }
}

// ----------------------------------------------------------------------------

XclImpNameManager::XclImpNameManager( const XclImpRoot& rRoot ) :
    XclImpRoot( rRoot )
{
}

void XclImpNameManager::ReadName( XclImpStream& rStrm )
{
    ULONG nCount = maNameList.Count();
    if( nCount < 0xFFFF )
        maNameList.Append( new XclImpName( rStrm, static_cast< sal_uInt16 >( nCount + 1 ) ) );
}

const XclImpName* XclImpNameManager::FindName( const String& rXclName, SCTAB nScTab ) const
{
    const XclImpName* pGlobalName = 0;   // a found global name
    const XclImpName* pLocalName = 0;    // a found local name
    for( const XclImpName* pName = maNameList.First(); pName && !pLocalName; pName = maNameList.Next() )
    {
        if( pName->GetXclName() == rXclName )
        {
            if( pName->GetScTab() == nScTab )
                pLocalName = pName;
            else if( pName->IsGlobal() )
                pGlobalName = pName;
        }
    }
    return pLocalName ? pLocalName : pGlobalName;
}

const XclImpName* XclImpNameManager::GetName( sal_uInt16 nXclNameIdx ) const
{
    DBG_ASSERT( nXclNameIdx > 0, "XclImpNameManager::GetName - index must be >0" );
    return maNameList.GetObject( nXclNameIdx - 1 );
}

// ============================================================================

<|endoftext|>