<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "rdb_protocol/artificial_table/caching_cfeed_backend.hpp"

#include "rdb_protocol/env.hpp"

void caching_cfeed_artificial_table_backend_t::notify_row(const ql::datum_t &pkey) {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        /* If `all_dirty` is true don't bother storing this individual row */
        if (caching_machinery->all_dirty || caching_machinery->all_dirty_break) {
            return;
        }
        caching_machinery->dirty.insert(pkey);
        if (caching_machinery->waker != nullptr) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

void caching_cfeed_artificial_table_backend_t::notify_all() {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        caching_machinery->all_dirty = true;
        if (caching_machinery->waker) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

void caching_cfeed_artificial_table_backend_t::notify_break() {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        caching_machinery->all_dirty_break = true;
        if (caching_machinery->waker) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

caching_cfeed_artificial_table_backend_t::caching_machinery_t::caching_machinery_t(
            caching_cfeed_artificial_table_backend_t *_parent) :
        parent(_parent),
        all_dirty(false),
        /* Set `all_dirty_break` to `true` to force an initial recomputation. The reason
        for using `all_dirty_break` instead of `all_dirty` is that there are no
        subscribers, so we can save a few CPU cycles by not computing the diff. */
        all_dirty_break(true),
        waker(nullptr) {
    guarantee(parent->caching_machinery == nullptr);
    parent->caching_machinery = this;
    coro_t::spawn_sometime(std::bind(&caching_machinery_t::run, this, drainer.lock()));
}

caching_cfeed_artificial_table_backend_t::caching_machinery_t::~caching_machinery_t() {
    guarantee(parent->caching_machinery == this);
    parent->caching_machinery = nullptr;
}

void caching_cfeed_artificial_table_backend_t::caching_machinery_t::run(
        auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING {
    parent->set_notifications(true);
    try {
        while (true) {
            /* Copy the dirtiness flags into local variables and reset them. Resetting
            them now is important because it means that notifications that arrive while
            we're processing the current batch will be queued up instead of ignored. */
            std::set<ql::datum_t, latest_version_optional_datum_less_t> local_dirty;
            bool local_all_dirty = false, local_all_dirty_break = false;
            std::swap(dirty, local_dirty);
            std::swap(all_dirty, local_all_dirty);
            std::swap(all_dirty_break, local_all_dirty_break);

            guarantee(local_all_dirty || local_all_dirty_break || !local_dirty.empty(),
                "If nothing is dirty, we shouldn't have gotten here");

            bool error = false;
            if (local_all_dirty || local_all_dirty_break) {
                if (!diff_all(local_all_dirty_break, keepalive.get_drain_signal())) {
                    error = true;
                } else {
                    ready.pulse_if_not_already_pulsed();
                }
            } else {
                for (const auto &key : local_dirty) {
                    if (!diff_one(key, keepalive.get_drain_signal())) {
                        error = true;
                        break;
                    }
                }
            }

            if (error) {
                /* Kick off any subscribers since we got an error. */
                send_all_stop();
                /* Ensure that we try again the next time around the loop. */
                all_dirty = true;
                /* Go around the loop and try again. But first wait a second so we
                don't eat too much CPU if it keeps failing. */
                nap(1000, keepalive.get_drain_signal());
                continue;
            }

            /* Wait until the next change */
            if (dirty.empty() && !all_dirty) {
                cond_t cond;
                assignment_sentry_t<cond_t *> cond_sentry(&waker, &cond);
                wait_interruptible(&cond, keepalive.get_drain_signal());
            }
        }
    } catch (const interrupted_exc_t &) {
        /* break out of the loop */
    }
    parent->set_notifications(false);
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::diff_one(
        const ql::datum_t &key, signal_t *interruptor) {
    /* Fetch new value from backend */
    ql::datum_t new_val;
    std::string error;
    if (!parent->read_row(key, interruptor, &new_val, &error)) {
        return false;
    }
    /* Fetch old value from `old_values` map */
    ql::datum_t old_val;
    auto it = old_values.find(store_key_t(key.print_primary()));
    if (it != old_values.end()) {
        old_val = it->second;
    }
    /* Update `old_values` map */
    if (!new_val.has()) {
        if (it != old_values.end()) {
            old_values.erase(it);
        }
    } else {
        if (it != old_values.end()) {
            it->second = new_val;
        } else {
            old_values.insert(std::make_pair(store_key_t(key.print_primary()), new_val));
        }
    }
    /* Send notification if it actually changed */
    if (new_val != old_val) {
        send_all_change(store_key_t(key.print_primary()), old_val, new_val);
    }
    return true;
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::diff_all(
        bool is_break, signal_t *interruptor) {
    /* Fetch the new values of everything */
    std::map<store_key_t, ql::datum_t> new_values;
    if (!get_values(interruptor, &new_values)) {
        return false;
    }
    if (is_break) {
        /* Don't bother with the diff; just kick off all the subscribers */
        send_all_stop();
    } else {
        /* Diff old values against new values and notify subscribers */
        auto old_it = old_values.begin();
        auto new_it = new_values.begin();
        while (old_it != old_values.end() || new_it != new_values.end()) {
            if (old_it == old_values.end() ||
                    (new_it != new_values.end() && new_it->first < old_it->first)) {
                send_all_change(new_it->first, ql::datum_t(), new_it->second);
                ++new_it;
            } else if (new_it == new_values.end() ||
                    (old_it != old_values.end() && old_it->first < new_it->first)) {
                send_all_change(old_it->first, old_it->second, ql::datum_t());
                ++old_it;
            } else {
                guarantee(old_it != old_values.end());
                guarantee(new_it != new_values.end());
                guarantee(old_it->first == new_it->first);
                if (old_it->second != new_it->second) {
                    send_all_change(old_it->first, old_it->second, new_it->second);
                }
                ++old_it;
                ++new_it;
            }
        }
    }
    old_values = std::move(new_values);
    return true;
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::get_values(
        signal_t *interruptor, std::map<store_key_t, ql::datum_t> *out) {
    out->clear();
    std::string error;
    counted_t<ql::datum_stream_t> stream;
    if (!parent->read_all_rows_as_stream(
            ql::protob_t<const Backtrace>(),
            ql::datum_range_t::universe(),
            sorting_t::UNORDERED,
            interruptor,
            &stream,
            &error)) {
        return false;
    }
    guarantee(!stream->is_cfeed());
    ql::env_t env(interruptor, reql_version_t::LATEST);
    while (!stream->is_exhausted()) {
        std::vector<ql::datum_t> datums;
        try {
            datums = stream->next_batch(&env, ql::batchspec_t::all());
        } catch (const ql::base_exc_t &) {
            return false;
        }
        for (const ql::datum_t &doc : datums) {
            ql::datum_t key = doc.get_field(
                datum_string_t(parent->get_primary_key_name()),
                ql::NOTHROW);
            guarantee(key.has());
            store_key_t key2(key.print_primary());
            auto pair = out->insert(std::make_pair(key2, doc));
            guarantee(pair.second);
        }
    }
    return true;
}

scoped_ptr_t<cfeed_artificial_table_backend_t::machinery_t>
        caching_cfeed_artificial_table_backend_t::
            construct_changefeed_machinery(signal_t *interruptor) {
    scoped_ptr_t<caching_machinery_t> m(new caching_machinery_t(this));
    wait_interruptible(&m->ready, interruptor);
    return scoped_ptr_t<cfeed_artificial_table_backend_t::machinery_t>(m.release());
}

void timer_cfeed_artificial_table_backend_t::set_notifications(bool notify) {
    if (notify && !timer.has()) {
        timer.init(new repeating_timer_t(
            1000,
            [this]() { notify_all(); }
            ));
    }
    if (!notify && timer.has()) {
        timer.reset();
    }
}

<commit_msg>Assume that batchspec_t::all() forces the entire stream to be read.<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "rdb_protocol/artificial_table/caching_cfeed_backend.hpp"

#include "rdb_protocol/env.hpp"

void caching_cfeed_artificial_table_backend_t::notify_row(const ql::datum_t &pkey) {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        /* If `all_dirty` is true don't bother storing this individual row */
        if (caching_machinery->all_dirty || caching_machinery->all_dirty_break) {
            return;
        }
        caching_machinery->dirty.insert(pkey);
        if (caching_machinery->waker != nullptr) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

void caching_cfeed_artificial_table_backend_t::notify_all() {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        caching_machinery->all_dirty = true;
        if (caching_machinery->waker) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

void caching_cfeed_artificial_table_backend_t::notify_break() {
    ASSERT_FINITE_CORO_WAITING;
    if (caching_machinery != nullptr) {
        caching_machinery->all_dirty_break = true;
        if (caching_machinery->waker) {
            caching_machinery->waker->pulse_if_not_already_pulsed();
        }
    }
}

caching_cfeed_artificial_table_backend_t::caching_machinery_t::caching_machinery_t(
            caching_cfeed_artificial_table_backend_t *_parent) :
        parent(_parent),
        all_dirty(false),
        /* Set `all_dirty_break` to `true` to force an initial recomputation. The reason
        for using `all_dirty_break` instead of `all_dirty` is that there are no
        subscribers, so we can save a few CPU cycles by not computing the diff. */
        all_dirty_break(true),
        waker(nullptr) {
    guarantee(parent->caching_machinery == nullptr);
    parent->caching_machinery = this;
    coro_t::spawn_sometime(std::bind(&caching_machinery_t::run, this, drainer.lock()));
}

caching_cfeed_artificial_table_backend_t::caching_machinery_t::~caching_machinery_t() {
    guarantee(parent->caching_machinery == this);
    parent->caching_machinery = nullptr;
}

void caching_cfeed_artificial_table_backend_t::caching_machinery_t::run(
        auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING {
    parent->set_notifications(true);
    try {
        while (true) {
            /* Copy the dirtiness flags into local variables and reset them. Resetting
            them now is important because it means that notifications that arrive while
            we're processing the current batch will be queued up instead of ignored. */
            std::set<ql::datum_t, latest_version_optional_datum_less_t> local_dirty;
            bool local_all_dirty = false, local_all_dirty_break = false;
            std::swap(dirty, local_dirty);
            std::swap(all_dirty, local_all_dirty);
            std::swap(all_dirty_break, local_all_dirty_break);

            guarantee(local_all_dirty || local_all_dirty_break || !local_dirty.empty(),
                "If nothing is dirty, we shouldn't have gotten here");

            bool error = false;
            if (local_all_dirty || local_all_dirty_break) {
                if (!diff_all(local_all_dirty_break, keepalive.get_drain_signal())) {
                    error = true;
                } else {
                    ready.pulse_if_not_already_pulsed();
                }
            } else {
                for (const auto &key : local_dirty) {
                    if (!diff_one(key, keepalive.get_drain_signal())) {
                        error = true;
                        break;
                    }
                }
            }

            if (error) {
                /* Kick off any subscribers since we got an error. */
                send_all_stop();
                /* Ensure that we try again the next time around the loop. */
                all_dirty = true;
                /* Go around the loop and try again. But first wait a second so we
                don't eat too much CPU if it keeps failing. */
                nap(1000, keepalive.get_drain_signal());
                continue;
            }

            /* Wait until the next change */
            if (dirty.empty() && !all_dirty) {
                cond_t cond;
                assignment_sentry_t<cond_t *> cond_sentry(&waker, &cond);
                wait_interruptible(&cond, keepalive.get_drain_signal());
            }
        }
    } catch (const interrupted_exc_t &) {
        /* break out of the loop */
    }
    parent->set_notifications(false);
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::diff_one(
        const ql::datum_t &key, signal_t *interruptor) {
    /* Fetch new value from backend */
    ql::datum_t new_val;
    std::string error;
    if (!parent->read_row(key, interruptor, &new_val, &error)) {
        return false;
    }
    /* Fetch old value from `old_values` map */
    ql::datum_t old_val;
    auto it = old_values.find(store_key_t(key.print_primary()));
    if (it != old_values.end()) {
        old_val = it->second;
    }
    /* Update `old_values` map */
    if (!new_val.has()) {
        if (it != old_values.end()) {
            old_values.erase(it);
        }
    } else {
        if (it != old_values.end()) {
            it->second = new_val;
        } else {
            old_values.insert(std::make_pair(store_key_t(key.print_primary()), new_val));
        }
    }
    /* Send notification if it actually changed */
    if (new_val != old_val) {
        send_all_change(store_key_t(key.print_primary()), old_val, new_val);
    }
    return true;
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::diff_all(
        bool is_break, signal_t *interruptor) {
    /* Fetch the new values of everything */
    std::map<store_key_t, ql::datum_t> new_values;
    if (!get_values(interruptor, &new_values)) {
        return false;
    }
    if (is_break) {
        /* Don't bother with the diff; just kick off all the subscribers */
        send_all_stop();
    } else {
        /* Diff old values against new values and notify subscribers */
        auto old_it = old_values.begin();
        auto new_it = new_values.begin();
        while (old_it != old_values.end() || new_it != new_values.end()) {
            if (old_it == old_values.end() ||
                    (new_it != new_values.end() && new_it->first < old_it->first)) {
                send_all_change(new_it->first, ql::datum_t(), new_it->second);
                ++new_it;
            } else if (new_it == new_values.end() ||
                    (old_it != old_values.end() && old_it->first < new_it->first)) {
                send_all_change(old_it->first, old_it->second, ql::datum_t());
                ++old_it;
            } else {
                guarantee(old_it != old_values.end());
                guarantee(new_it != new_values.end());
                guarantee(old_it->first == new_it->first);
                if (old_it->second != new_it->second) {
                    send_all_change(old_it->first, old_it->second, new_it->second);
                }
                ++old_it;
                ++new_it;
            }
        }
    }
    old_values = std::move(new_values);
    return true;
}

bool caching_cfeed_artificial_table_backend_t::caching_machinery_t::get_values(
        signal_t *interruptor, std::map<store_key_t, ql::datum_t> *out) {
    out->clear();
    std::string error;
    counted_t<ql::datum_stream_t> stream;
    if (!parent->read_all_rows_as_stream(
            ql::protob_t<const Backtrace>(),
            ql::datum_range_t::universe(),
            sorting_t::UNORDERED,
            interruptor,
            &stream,
            &error)) {
        return false;
    }
    guarantee(!stream->is_cfeed());
    ql::env_t env(interruptor, reql_version_t::LATEST);
    std::vector<ql::datum_t> datums;
    try {
        datums = stream->next_batch(&env, ql::batchspec_t::all());
    } catch (const ql::base_exc_t &) {
        return false;
    }
    guarantee(stream->is_exhausted(), "We expect ql::batchspec_t::all() to read the "
        "entire stream");
    for (const ql::datum_t &doc : datums) {
        ql::datum_t key = doc.get_field(
            datum_string_t(parent->get_primary_key_name()),
            ql::NOTHROW);
        guarantee(key.has());
        store_key_t key2(key.print_primary());
        auto pair = out->insert(std::make_pair(key2, doc));
        guarantee(pair.second);
    }
    return true;
}

scoped_ptr_t<cfeed_artificial_table_backend_t::machinery_t>
        caching_cfeed_artificial_table_backend_t::
            construct_changefeed_machinery(signal_t *interruptor) {
    scoped_ptr_t<caching_machinery_t> m(new caching_machinery_t(this));
    wait_interruptible(&m->ready, interruptor);
    return scoped_ptr_t<cfeed_artificial_table_backend_t::machinery_t>(m.release());
}

void timer_cfeed_artificial_table_backend_t::set_notifications(bool notify) {
    if (notify && !timer.has()) {
        timer.init(new repeating_timer_t(
            1000,
            [this]() { notify_all(); }
            ));
    }
    if (!notify && timer.has()) {
        timer.reset();
    }
}

<|endoftext|>


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

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_implementation.h"

class GPUBrowserTest : public InProcessBrowserTest {
 protected:
  GPUBrowserTest() {
    EnableDOMAutomation();
  }

  virtual void SetUpInProcessBrowserTestFixture() {
    FilePath test_dir;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
    gpu_test_dir_ = test_dir.AppendASCII("gpu");
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    InProcessBrowserTest::SetUpCommandLine(command_line);

    EXPECT_TRUE(test_launcher_utils::OverrideGLImplementation(
        command_line,
        gfx::kGLImplementationOSMesaName));

    command_line->AppendSwitch(switches::kDisablePopupBlocking);

#if defined(OS_MACOSX)
    // Accelerated compositing does not work with OSMesa. AcceleratedSurface
    // assumes GL contexts are native.
    command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
#endif
  }

  FilePath gpu_test_dir_;
};

#if defined(TOOLKIT_VIEWS)
// Flaky on Windows (dbg): http://crbug.com/72608
// For ChromeOS: http://crbug.com/76217
#define MAYBE_BrowserTestCanLaunchWithOSMesa DISABLED_BrowserTestCanLaunchWithOSMesa
#else
#define MAYBE_BrowserTestCanLaunchWithOSMesa BrowserTestCanLaunchWithOSMesa
#endif

IN_PROC_BROWSER_TEST_F(GPUBrowserTest, MAYBE_BrowserTestCanLaunchWithOSMesa) {
  // Check the webgl test reports success and that the renderer was OSMesa.
  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("webgl.html")));

  EXPECT_EQ(ASCIIToUTF16("SUCCESS: WebKit WebGL"),
            browser()->GetSelectedTabContents()->GetTitle());
}

IN_PROC_BROWSER_TEST_F(GPUBrowserTest, CanOpenPopupAndRenderWithWebGLCanvas) {
  ui_test_utils::DOMMessageQueue message_queue;

  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("webgl_popup.html")));

  std::string result;
  ASSERT_TRUE(message_queue.WaitForMessage(&result));
  EXPECT_EQ("\"SUCCESS\"", result);
}

IN_PROC_BROWSER_TEST_F(GPUBrowserTest, CanOpenPopupAndRenderWith2DCanvas) {
  ui_test_utils::DOMMessageQueue message_queue;

  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("canvas_popup.html")));

  std::string result;
  ASSERT_TRUE(message_queue.WaitForMessage(&result));
  EXPECT_EQ("\"SUCCESS\"", result);
}
<commit_msg><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 "base/command_line.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_implementation.h"

class GPUBrowserTest : public InProcessBrowserTest {
 protected:
  GPUBrowserTest() {
    EnableDOMAutomation();
  }

  virtual void SetUpInProcessBrowserTestFixture() {
    FilePath test_dir;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
    gpu_test_dir_ = test_dir.AppendASCII("gpu");
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    InProcessBrowserTest::SetUpCommandLine(command_line);

    EXPECT_TRUE(test_launcher_utils::OverrideGLImplementation(
        command_line,
        gfx::kGLImplementationOSMesaName));

    command_line->AppendSwitch(switches::kDisablePopupBlocking);

#if defined(OS_MACOSX)
    // Accelerated compositing does not work with OSMesa. AcceleratedSurface
    // assumes GL contexts are native.
    command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
#endif
  }

  FilePath gpu_test_dir_;
};

#if defined(TOOLKIT_VIEWS)
// Flaky on Windows (dbg): http://crbug.com/72608
// For ChromeOS: http://crbug.com/76217
#define MAYBE_BrowserTestCanLaunchWithOSMesa DISABLED_BrowserTestCanLaunchWithOSMesa
#else
#define MAYBE_BrowserTestCanLaunchWithOSMesa BrowserTestCanLaunchWithOSMesa
#endif

IN_PROC_BROWSER_TEST_F(GPUBrowserTest, MAYBE_BrowserTestCanLaunchWithOSMesa) {
  // Check the webgl test reports success and that the renderer was OSMesa.
  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("webgl.html")));

  EXPECT_EQ(ASCIIToUTF16("SUCCESS: WebKit WebGL"),
            browser()->GetSelectedTabContents()->GetTitle());
}

// Test is flaky and timing out.  See crbug.com/99883
IN_PROC_BROWSER_TEST_F(GPUBrowserTest,
                       DISABLED_CanOpenPopupAndRenderWithWebGLCanvas) {
  ui_test_utils::DOMMessageQueue message_queue;

  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("webgl_popup.html")));

  std::string result;
  ASSERT_TRUE(message_queue.WaitForMessage(&result));
  EXPECT_EQ("\"SUCCESS\"", result);
}

IN_PROC_BROWSER_TEST_F(GPUBrowserTest, CanOpenPopupAndRenderWith2DCanvas) {
  ui_test_utils::DOMMessageQueue message_queue;

  ui_test_utils::NavigateToURL(
      browser(),
      net::FilePathToFileURL(gpu_test_dir_.AppendASCII("canvas_popup.html")));

  std::string result;
  ASSERT_TRUE(message_queue.WaitForMessage(&result));
  EXPECT_EQ("\"SUCCESS\"", result);
}
<|endoftext|>


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

#include "chrome/browser/gtk/infobar_gtk.h"

#include <gtk/gtk.h>

#include "base/gfx/gtk_util.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
#include "chrome/browser/gtk/link_button_gtk.h"
#include "chrome/common/gtk_util.h"

namespace {

// TODO(estade): The background should be a gradient. For now we just use this
// solid color.
const GdkColor kBackgroundColor = GDK_COLOR_RGB(250, 230, 145);

// Border color (the top pixel of the infobar).
const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);

// The total height of the info bar.
const int kInfoBarHeight = 37;

// Pixels between infobar elements.
const int kElementPadding = 5;

// Extra padding on either end of info bar.
const int kLeftPadding = 5;
const int kRightPadding = 5;

}  // namespace

InfoBar::InfoBar(InfoBarDelegate* delegate)
    : container_(NULL),
      delegate_(delegate) {
  // Create |hbox_| and pad the sides.
  hbox_ = gtk_hbox_new(FALSE, kElementPadding);
  GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1);
  gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
      0, 0, kLeftPadding, kRightPadding);

  GtkWidget* bg_box = gtk_event_box_new();
  gtk_container_add(GTK_CONTAINER(padding), hbox_);
  gtk_container_add(GTK_CONTAINER(bg_box), padding);

  // Set the top border and background color.
  gtk_widget_modify_bg(bg_box, GTK_STATE_NORMAL, &kBackgroundColor);
  border_bin_.Own(gfx::CreateGtkBorderBin(bg_box, &kBorderColor,
                                          1, 0, 0, 0));
  gtk_widget_set_size_request(border_bin_.get(), -1, kInfoBarHeight);

  // Add the icon on the left, if any.
  SkBitmap* icon = delegate->GetIcon();
  if (icon) {
    GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
    GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
    g_object_unref(pixbuf);
    gtk_box_pack_start(GTK_BOX(hbox_), image, FALSE, FALSE, 0);
  }

  close_button_.reset(CustomDrawButton::AddBarCloseButton(hbox_));
  g_signal_connect(close_button_->widget(), "clicked",
                   G_CALLBACK(OnCloseButton), this);

  slide_widget_.reset(new SlideAnimatorGtk(border_bin_.get(),
                                           SlideAnimatorGtk::DOWN,
                                           0, true, this));
  // We store a pointer back to |this| so we can refer to it from the infobar
  // container.
  g_object_set_data(G_OBJECT(slide_widget_->widget()), "info-bar", this);
}

InfoBar::~InfoBar() {
  border_bin_.Destroy();
}

GtkWidget* InfoBar::widget() {
  return slide_widget_->widget();
}

void InfoBar::AnimateOpen() {
  slide_widget_->Open();
}

void InfoBar::Open() {
  slide_widget_->OpenWithoutAnimation();
}

void InfoBar::AnimateClose() {
  slide_widget_->Close();
}

void InfoBar::Close() {
  if (delegate_) {
    delegate_->InfoBarClosed();
    delegate_ = NULL;
  }
  delete this;
}

void InfoBar::RemoveInfoBar() const {
  container_->RemoveDelegate(delegate_);
}

void InfoBar::Closed() {
  Close();
}

// static
void InfoBar::OnCloseButton(GtkWidget* button, InfoBar* info_bar) {
  info_bar->AnimateClose();
}

// AlertInfoBar ----------------------------------------------------------------

class AlertInfoBar : public InfoBar {
 public:
  AlertInfoBar(AlertInfoBarDelegate* delegate)
      : InfoBar(delegate) {
    std::wstring text = delegate->GetMessageText();
    GtkWidget* label = gtk_label_new(WideToUTF8(text).c_str());
    gtk_box_pack_start(GTK_BOX(hbox_), label, FALSE, FALSE, 0);
  }
};

// LinkInfoBar -----------------------------------------------------------------

class LinkInfoBar : public InfoBar {
 public:
  LinkInfoBar(LinkInfoBarDelegate* delegate)
      : InfoBar(delegate) {
    size_t link_offset;
    std::wstring display_text =
        delegate->GetMessageTextWithOffset(&link_offset);
    std::wstring link_text = delegate->GetLinkText();

    // Create the link button.
    link_button_.reset(new LinkButtonGtk(WideToUTF8(link_text).c_str()));
    g_signal_connect(link_button_->widget(), "clicked",
                     G_CALLBACK(OnLinkClick), this);

    // If link_offset is npos, we right-align the link instead of embedding it
    // in the text.
    if (link_offset == std::wstring::npos) {
      gtk_box_pack_end(GTK_BOX(hbox_), link_button_->widget(), FALSE, FALSE, 0);
      GtkWidget* label = gtk_label_new(WideToUTF8(display_text).c_str());
      gtk_box_pack_start(GTK_BOX(hbox_), label, FALSE, FALSE, 0);
    } else {
      GtkWidget* initial_label = gtk_label_new(
          WideToUTF8(display_text.substr(0, link_offset)).c_str());
      GtkWidget* trailing_label = gtk_label_new(
          WideToUTF8(display_text.substr(link_offset)).c_str());

      // We don't want any spacing between the elements, so we pack them into
      // this hbox that doesn't use kElementPadding.
      // TODO(estade): we need to reduce the padding on the button, because
      // currently the link has extra space on either side and it looks odd.
      GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), link_button_->widget(),
                         FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox_), hbox, FALSE, FALSE, 0);
    }
  }

 private:
  static void OnLinkClick(GtkWidget* button, LinkInfoBar* link_info_bar) {
    // TODO(estade): we need an equivalent for DispositionFromEventFlags().
    if (link_info_bar->delegate_->AsLinkInfoBarDelegate()->
        LinkClicked(CURRENT_TAB)) {
      link_info_bar->RemoveInfoBar();
    }
  }

  // The clickable link text.
  scoped_ptr<LinkButtonGtk> link_button_;
};

// ConfirmInfoBar --------------------------------------------------------------

class ConfirmInfoBar : public AlertInfoBar {
 public:
  ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
      : AlertInfoBar(delegate) {
    AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
    AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK);
  }

 private:
  // Adds a button to the info bar by type. It will do nothing if the delegate
  // doesn't specify a button of the given type.
  void AddConfirmButton(ConfirmInfoBarDelegate::InfoBarButton type) {
    if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) {
      GtkWidget* button = gtk_button_new_with_label(WideToUTF8(
          delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str());
      GtkWidget* centering_vbox = gtk_vbox_new(FALSE, 0);
      gtk_box_pack_end(GTK_BOX(centering_vbox), button, TRUE, FALSE, 0);
      gtk_box_pack_end(GTK_BOX(hbox_), centering_vbox, FALSE, FALSE, 0);
      g_signal_connect(button, "clicked",
                       G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ?
                                  OnOkButton : OnCancelButton),
                       this);
    }
  }

  static void OnCancelButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
    if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Cancel())
      info_bar->RemoveInfoBar();
  }

  static void OnOkButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
    if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Accept())
      info_bar->RemoveInfoBar();
  }
};

// AlertInfoBarDelegate, InfoBarDelegate overrides: ----------------------------

InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
  return new AlertInfoBar(this);
}

// LinkInfoBarDelegate, InfoBarDelegate overrides: -----------------------------

InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
  return new LinkInfoBar(this);
}

// ConfirmInfoBarDelegate, InfoBarDelegate overrides: --------------------------

InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
  return new ConfirmInfoBar(this);
}
<commit_msg>Remove outdated comment. No code change.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/infobar_gtk.h"

#include <gtk/gtk.h>

#include "base/gfx/gtk_util.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
#include "chrome/browser/gtk/link_button_gtk.h"
#include "chrome/common/gtk_util.h"

namespace {

// TODO(estade): The background should be a gradient. For now we just use this
// solid color.
const GdkColor kBackgroundColor = GDK_COLOR_RGB(250, 230, 145);

// Border color (the top pixel of the infobar).
const GdkColor kBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);

// The total height of the info bar.
const int kInfoBarHeight = 37;

// Pixels between infobar elements.
const int kElementPadding = 5;

// Extra padding on either end of info bar.
const int kLeftPadding = 5;
const int kRightPadding = 5;

}  // namespace

InfoBar::InfoBar(InfoBarDelegate* delegate)
    : container_(NULL),
      delegate_(delegate) {
  // Create |hbox_| and pad the sides.
  hbox_ = gtk_hbox_new(FALSE, kElementPadding);
  GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1);
  gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
      0, 0, kLeftPadding, kRightPadding);

  GtkWidget* bg_box = gtk_event_box_new();
  gtk_container_add(GTK_CONTAINER(padding), hbox_);
  gtk_container_add(GTK_CONTAINER(bg_box), padding);

  // Set the top border and background color.
  gtk_widget_modify_bg(bg_box, GTK_STATE_NORMAL, &kBackgroundColor);
  border_bin_.Own(gfx::CreateGtkBorderBin(bg_box, &kBorderColor,
                                          1, 0, 0, 0));
  gtk_widget_set_size_request(border_bin_.get(), -1, kInfoBarHeight);

  // Add the icon on the left, if any.
  SkBitmap* icon = delegate->GetIcon();
  if (icon) {
    GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
    GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
    g_object_unref(pixbuf);
    gtk_box_pack_start(GTK_BOX(hbox_), image, FALSE, FALSE, 0);
  }

  close_button_.reset(CustomDrawButton::AddBarCloseButton(hbox_));
  g_signal_connect(close_button_->widget(), "clicked",
                   G_CALLBACK(OnCloseButton), this);

  slide_widget_.reset(new SlideAnimatorGtk(border_bin_.get(),
                                           SlideAnimatorGtk::DOWN,
                                           0, true, this));
  // We store a pointer back to |this| so we can refer to it from the infobar
  // container.
  g_object_set_data(G_OBJECT(slide_widget_->widget()), "info-bar", this);
}

InfoBar::~InfoBar() {
  border_bin_.Destroy();
}

GtkWidget* InfoBar::widget() {
  return slide_widget_->widget();
}

void InfoBar::AnimateOpen() {
  slide_widget_->Open();
}

void InfoBar::Open() {
  slide_widget_->OpenWithoutAnimation();
}

void InfoBar::AnimateClose() {
  slide_widget_->Close();
}

void InfoBar::Close() {
  if (delegate_) {
    delegate_->InfoBarClosed();
    delegate_ = NULL;
  }
  delete this;
}

void InfoBar::RemoveInfoBar() const {
  container_->RemoveDelegate(delegate_);
}

void InfoBar::Closed() {
  Close();
}

// static
void InfoBar::OnCloseButton(GtkWidget* button, InfoBar* info_bar) {
  info_bar->AnimateClose();
}

// AlertInfoBar ----------------------------------------------------------------

class AlertInfoBar : public InfoBar {
 public:
  AlertInfoBar(AlertInfoBarDelegate* delegate)
      : InfoBar(delegate) {
    std::wstring text = delegate->GetMessageText();
    GtkWidget* label = gtk_label_new(WideToUTF8(text).c_str());
    gtk_box_pack_start(GTK_BOX(hbox_), label, FALSE, FALSE, 0);
  }
};

// LinkInfoBar -----------------------------------------------------------------

class LinkInfoBar : public InfoBar {
 public:
  LinkInfoBar(LinkInfoBarDelegate* delegate)
      : InfoBar(delegate) {
    size_t link_offset;
    std::wstring display_text =
        delegate->GetMessageTextWithOffset(&link_offset);
    std::wstring link_text = delegate->GetLinkText();

    // Create the link button.
    link_button_.reset(new LinkButtonGtk(WideToUTF8(link_text).c_str()));
    g_signal_connect(link_button_->widget(), "clicked",
                     G_CALLBACK(OnLinkClick), this);

    // If link_offset is npos, we right-align the link instead of embedding it
    // in the text.
    if (link_offset == std::wstring::npos) {
      gtk_box_pack_end(GTK_BOX(hbox_), link_button_->widget(), FALSE, FALSE, 0);
      GtkWidget* label = gtk_label_new(WideToUTF8(display_text).c_str());
      gtk_box_pack_start(GTK_BOX(hbox_), label, FALSE, FALSE, 0);
    } else {
      GtkWidget* initial_label = gtk_label_new(
          WideToUTF8(display_text.substr(0, link_offset)).c_str());
      GtkWidget* trailing_label = gtk_label_new(
          WideToUTF8(display_text.substr(link_offset)).c_str());

      // We don't want any spacing between the elements, so we pack them into
      // this hbox that doesn't use kElementPadding.
      GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), link_button_->widget(),
                         FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0);
      gtk_box_pack_start(GTK_BOX(hbox_), hbox, FALSE, FALSE, 0);
    }
  }

 private:
  static void OnLinkClick(GtkWidget* button, LinkInfoBar* link_info_bar) {
    // TODO(estade): we need an equivalent for DispositionFromEventFlags().
    if (link_info_bar->delegate_->AsLinkInfoBarDelegate()->
        LinkClicked(CURRENT_TAB)) {
      link_info_bar->RemoveInfoBar();
    }
  }

  // The clickable link text.
  scoped_ptr<LinkButtonGtk> link_button_;
};

// ConfirmInfoBar --------------------------------------------------------------

class ConfirmInfoBar : public AlertInfoBar {
 public:
  ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
      : AlertInfoBar(delegate) {
    AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
    AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK);
  }

 private:
  // Adds a button to the info bar by type. It will do nothing if the delegate
  // doesn't specify a button of the given type.
  void AddConfirmButton(ConfirmInfoBarDelegate::InfoBarButton type) {
    if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) {
      GtkWidget* button = gtk_button_new_with_label(WideToUTF8(
          delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str());
      GtkWidget* centering_vbox = gtk_vbox_new(FALSE, 0);
      gtk_box_pack_end(GTK_BOX(centering_vbox), button, TRUE, FALSE, 0);
      gtk_box_pack_end(GTK_BOX(hbox_), centering_vbox, FALSE, FALSE, 0);
      g_signal_connect(button, "clicked",
                       G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ?
                                  OnOkButton : OnCancelButton),
                       this);
    }
  }

  static void OnCancelButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
    if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Cancel())
      info_bar->RemoveInfoBar();
  }

  static void OnOkButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
    if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Accept())
      info_bar->RemoveInfoBar();
  }
};

// AlertInfoBarDelegate, InfoBarDelegate overrides: ----------------------------

InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
  return new AlertInfoBar(this);
}

// LinkInfoBarDelegate, InfoBarDelegate overrides: -----------------------------

InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
  return new LinkInfoBar(this);
}

// ConfirmInfoBarDelegate, InfoBarDelegate overrides: --------------------------

InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
  return new ConfirmInfoBar(this);
}
<|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 "chrome/browser/history/snippet.h"

#include <algorithm>

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "unicode/brkiter.h"
#include "unicode/utext.h"
#include "unicode/utf8.h"

namespace {

bool PairFirstLessThan(const Snippet::MatchPosition& a,
                       const Snippet::MatchPosition& b) {
  return a.first < b.first;
}

// Combines all pairs after offset in match_positions that are contained
// or touch the pair at offset.
void CoalescePositionsFrom(size_t offset,
                           Snippet::MatchPositions* match_positions) {
  DCHECK(offset < match_positions->size());
  Snippet::MatchPosition& pair((*match_positions)[offset]);
  ++offset;
  while (offset < match_positions->size() &&
         pair.second >= (*match_positions)[offset].first) {
    pair.second = std::max(pair.second, (*match_positions)[offset].second);
    match_positions->erase(match_positions->begin() + offset);
  }
}

// Makes sure there is a pair in match_positions that contains the specified
// range. This keeps the pairs ordered in match_positions by first, and makes
// sure none of the pairs in match_positions touch each other.
void AddMatch(size_t start,
              size_t end,
              Snippet::MatchPositions* match_positions) {
  DCHECK(start < end);
  DCHECK(match_positions);
  Snippet::MatchPosition pair(start, end);
  if (match_positions->empty()) {
    match_positions->push_back(pair);
    return;
  }
  // There's at least one match. Find the position of the new match,
  // potentially extending pairs around it.
  Snippet::MatchPositions::iterator i =
      std::lower_bound(match_positions->begin(), match_positions->end(),
                       pair, &PairFirstLessThan);
  if (i != match_positions->end() && i->first == start) {
    // Match not at the end and there is already a pair with the same
    // start.
    if (end > i->second) {
      // New pair extends beyond existing pair. Extend existing pair and
      // coalesce matches after it.
      i->second = end;
      CoalescePositionsFrom(i - match_positions->begin(), match_positions);
    } // else case, new pair completely contained in existing pair, nothing
      // to do.
  } else if (i == match_positions->begin()) {
    // Match at the beginning and the first pair doesn't have the same
    // start. Insert new pair and coalesce matches after it.
    match_positions->insert(i, pair);
    CoalescePositionsFrom(0, match_positions);
  } else {
    // Not at the beginning (but may be at the end).
    --i;
    if (start <= i->second && end > i->second) {
      // Previous element contains match. Extend it and coalesce.
      i->second = end;
      CoalescePositionsFrom(i - match_positions->begin(), match_positions);
    } else if (end > i->second) {
      // Region doesn't touch previous element. See if region touches current
      // element.
      ++i;
      if (i == match_positions->end() || end < i->first) {
        match_positions->insert(i, pair);
      } else {
        i->first = start;
        i->second = end;
        CoalescePositionsFrom(i - match_positions->begin(), match_positions);
      }
    }
  }
}

// Converts an index in a utf8 string into the index in the corresponding wide
// string and returns the wide index. This is intended to be called in a loop
// iterating through a utf8 string.
//
// utf8_string: the utf8 string.
// utf8_length: length of the utf8 string.
// offset: the utf8 offset to convert.
// utf8_pos: current offset in the utf8 string. This is modified and on return
//           matches offset.
// wide_pos: current index in the wide string. This is the same as the return
//           value.
size_t AdvanceAndReturnWidePos(const char* utf8_string,
                               int32_t utf8_length,
                               int32_t offset,
                               int32_t* utf8_pos,
                               size_t* wide_pos) {
  DCHECK(offset >= *utf8_pos && offset <= utf8_length);

  UChar32 wide_char;
  while (*utf8_pos < offset) {
    U8_NEXT(utf8_string, *utf8_pos, utf8_length, wide_char);
    *wide_pos += (wide_char <= 0xFFFF) ? 1 : 2;
  }
  return *wide_pos;
}

// Given a character break iterator over a UTF-8 string, set the iterator
// position to |*utf8_pos| and move by |count| characters. |count| can
// be either positive or negative.
void MoveByNGraphemes(BreakIterator* bi, int count, size_t* utf8_pos) {
  // Ignore the return value. A side effect of the current position
  // being set at or following |*utf8_pos| is exploited here.
  // It's simpler than calling following(n) and then previous().
  // isBoundary() is not very fast, but should be good enough for the
  // snippet generation. If not, revisit the way we scan in ComputeSnippet.
  bi->isBoundary(*utf8_pos);
  bi->next(count);
  *utf8_pos = static_cast<size_t>(bi->current());
}

// The amount of context to include for a given hit. Note that it's counted
// in terms of graphemes rather than bytes.
const int kSnippetContext = 50;

// Returns true if next match falls within a snippet window
// from the previous match. The window size is counted in terms
// of graphemes rather than bytes in UTF-8.
bool IsNextMatchWithinSnippetWindow(BreakIterator* bi,
                                    size_t previous_match_end,
                                    size_t next_match_start) {
  // If it's within a window in terms of bytes, it's certain
  // that it's within a window in terms of graphemes as well.
  if (next_match_start < previous_match_end + kSnippetContext)
    return true;
  bi->isBoundary(previous_match_end);
  // An alternative to this is to call |bi->next()| at most
  // kSnippetContext times, compare |bi->current()| with |next_match_start|
  // after each call and return early if possible. There are other
  // heuristics to speed things up if necessary, but it's not likely that
  // we need to bother.
  bi->next(kSnippetContext);
  int64 current = bi->current();
  return (next_match_start < static_cast<uint64>(current) ||
          current == BreakIterator::DONE);
}

}  // namespace

// static
void Snippet::ExtractMatchPositions(const std::string& offsets_str,
                                    const std::string& column_num,
                                    MatchPositions* match_positions) {
  DCHECK(match_positions);
  if (offsets_str.empty())
    return;
  std::vector<std::string> offsets;
  SplitString(offsets_str, ' ', &offsets);
  // SQLite offsets are sets of four integers:
  //   column, query term, match offset, match length
  // Matches within a string are marked by (start, end) pairs.
  for (size_t i = 0; i < offsets.size() - 3; i += 4) {
    if (offsets[i] != column_num)
      continue;
    const size_t start = atoi(offsets[i + 2].c_str());
    const size_t end = start + atoi(offsets[i + 3].c_str());
    AddMatch(start, end, match_positions);
  }
}

// static
void Snippet::ConvertMatchPositionsToWide(
    const std::string& utf8_string,
    Snippet::MatchPositions* match_positions) {
  DCHECK(match_positions);
  int32_t utf8_pos = 0;
  size_t wide_pos = 0;
  const char* utf8_cstring = utf8_string.c_str();
  const int32_t utf8_length = static_cast<int32_t>(utf8_string.size());
  for (Snippet::MatchPositions::iterator i = match_positions->begin();
       i != match_positions->end(); ++i) {
    i->first = AdvanceAndReturnWidePos(utf8_cstring, utf8_length,
                                       i->first, &utf8_pos, &wide_pos);
    i->second = AdvanceAndReturnWidePos(utf8_cstring, utf8_length,
                                        i->second, &utf8_pos, &wide_pos);
  }
}

void Snippet::ComputeSnippet(const MatchPositions& match_positions,
                             const std::string& document) {
  // The length of snippets we try to produce.
  // We can generate longer snippets but stop once we cross kSnippetMaxLength.
  const size_t kSnippetMaxLength = 200;
  const std::wstring kEllipsis = L" ... ";

  UText* document_utext = NULL;
  UErrorCode status = U_ZERO_ERROR;
  document_utext = utext_openUTF8(document_utext, document.data(),
                                  document.size(), &status);
  // Locale does not matter because there's no per-locale customization
  // for character iterator.
  scoped_ptr<BreakIterator> bi(
    BreakIterator::createCharacterInstance(Locale::getDefault(), status));
  bi->setText(document_utext, status);
  DCHECK(U_SUCCESS(status));

  // We build the snippet by iterating through the matches and then grabbing
  // context around each match.  If matches are near enough each other (within
  // kSnippetContext), we skip the "..." between them.
  std::wstring snippet;
  size_t start = 0;
  for (size_t i = 0; i < match_positions.size(); ++i) {
    // Some shorter names for the current match.
    const size_t match_start = match_positions[i].first;
    const size_t match_end = match_positions[i].second;

    // Add the context, if any, to show before the match.
    size_t context_start = match_start;
    MoveByNGraphemes(bi.get(), -kSnippetContext, &context_start);
    start = std::max(start, context_start);
    if (start < match_start) {
      if (start > 0)
        snippet += kEllipsis;
      snippet += UTF8ToWide(document.substr(start, match_start - start));
    }

    // Add the match.
    const size_t first = snippet.size();
    snippet += UTF8ToWide(document.substr(match_start,
                                          match_end - match_start));
    matches_.push_back(std::make_pair(first, snippet.size()));

    // Compute the context, if any, to show after the match.
    size_t end;
    // Check if the next match falls within our snippet window.
    if (i + 1 < match_positions.size() &&
        IsNextMatchWithinSnippetWindow(bi.get(), match_end,
            match_positions[i + 1].first)) {
      // Yes, it's within the window.  Make the end context extend just up
      // to the next match.
      end = match_positions[i + 1].first;
      snippet += UTF8ToWide(document.substr(match_end, end - match_end));
    } else {
      // No, there's either no next match or the next match is too far away.
      end = match_end;
      MoveByNGraphemes(bi.get(), kSnippetContext, &end);
      snippet += UTF8ToWide(document.substr(match_end, end - match_end));
      if (end < document.size())
        snippet += kEllipsis;
    }
    start = end;

    // Stop here if we have enough snippet computed.
    if (snippet.size() >= kSnippetMaxLength)
      break;
  }

  utext_close(document_utext);
  swap(text_, snippet);
}
<commit_msg>Linux: Add CHECKs to track down source of history std::string out of range exceptions. BUG=http://crbug.com/15261<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 "chrome/browser/history/snippet.h"

#include <algorithm>

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "unicode/brkiter.h"
#include "unicode/utext.h"
#include "unicode/utf8.h"

namespace {

bool PairFirstLessThan(const Snippet::MatchPosition& a,
                       const Snippet::MatchPosition& b) {
  return a.first < b.first;
}

// Combines all pairs after offset in match_positions that are contained
// or touch the pair at offset.
void CoalescePositionsFrom(size_t offset,
                           Snippet::MatchPositions* match_positions) {
  DCHECK(offset < match_positions->size());
  Snippet::MatchPosition& pair((*match_positions)[offset]);
  ++offset;
  while (offset < match_positions->size() &&
         pair.second >= (*match_positions)[offset].first) {
    pair.second = std::max(pair.second, (*match_positions)[offset].second);
    match_positions->erase(match_positions->begin() + offset);
  }
}

// Makes sure there is a pair in match_positions that contains the specified
// range. This keeps the pairs ordered in match_positions by first, and makes
// sure none of the pairs in match_positions touch each other.
void AddMatch(size_t start,
              size_t end,
              Snippet::MatchPositions* match_positions) {
  DCHECK(start < end);
  DCHECK(match_positions);
  Snippet::MatchPosition pair(start, end);
  if (match_positions->empty()) {
    match_positions->push_back(pair);
    return;
  }
  // There's at least one match. Find the position of the new match,
  // potentially extending pairs around it.
  Snippet::MatchPositions::iterator i =
      std::lower_bound(match_positions->begin(), match_positions->end(),
                       pair, &PairFirstLessThan);
  if (i != match_positions->end() && i->first == start) {
    // Match not at the end and there is already a pair with the same
    // start.
    if (end > i->second) {
      // New pair extends beyond existing pair. Extend existing pair and
      // coalesce matches after it.
      i->second = end;
      CoalescePositionsFrom(i - match_positions->begin(), match_positions);
    } // else case, new pair completely contained in existing pair, nothing
      // to do.
  } else if (i == match_positions->begin()) {
    // Match at the beginning and the first pair doesn't have the same
    // start. Insert new pair and coalesce matches after it.
    match_positions->insert(i, pair);
    CoalescePositionsFrom(0, match_positions);
  } else {
    // Not at the beginning (but may be at the end).
    --i;
    if (start <= i->second && end > i->second) {
      // Previous element contains match. Extend it and coalesce.
      i->second = end;
      CoalescePositionsFrom(i - match_positions->begin(), match_positions);
    } else if (end > i->second) {
      // Region doesn't touch previous element. See if region touches current
      // element.
      ++i;
      if (i == match_positions->end() || end < i->first) {
        match_positions->insert(i, pair);
      } else {
        i->first = start;
        i->second = end;
        CoalescePositionsFrom(i - match_positions->begin(), match_positions);
      }
    }
  }
}

// Converts an index in a utf8 string into the index in the corresponding wide
// string and returns the wide index. This is intended to be called in a loop
// iterating through a utf8 string.
//
// utf8_string: the utf8 string.
// utf8_length: length of the utf8 string.
// offset: the utf8 offset to convert.
// utf8_pos: current offset in the utf8 string. This is modified and on return
//           matches offset.
// wide_pos: current index in the wide string. This is the same as the return
//           value.
size_t AdvanceAndReturnWidePos(const char* utf8_string,
                               int32_t utf8_length,
                               int32_t offset,
                               int32_t* utf8_pos,
                               size_t* wide_pos) {
  DCHECK(offset >= *utf8_pos && offset <= utf8_length);

  UChar32 wide_char;
  while (*utf8_pos < offset) {
    U8_NEXT(utf8_string, *utf8_pos, utf8_length, wide_char);
    *wide_pos += (wide_char <= 0xFFFF) ? 1 : 2;
  }
  return *wide_pos;
}

// Given a character break iterator over a UTF-8 string, set the iterator
// position to |*utf8_pos| and move by |count| characters. |count| can
// be either positive or negative.
void MoveByNGraphemes(BreakIterator* bi, int count, size_t* utf8_pos) {
  // Ignore the return value. A side effect of the current position
  // being set at or following |*utf8_pos| is exploited here.
  // It's simpler than calling following(n) and then previous().
  // isBoundary() is not very fast, but should be good enough for the
  // snippet generation. If not, revisit the way we scan in ComputeSnippet.
  bi->isBoundary(*utf8_pos);
  bi->next(count);
  *utf8_pos = static_cast<size_t>(bi->current());
}

// The amount of context to include for a given hit. Note that it's counted
// in terms of graphemes rather than bytes.
const int kSnippetContext = 50;

// Returns true if next match falls within a snippet window
// from the previous match. The window size is counted in terms
// of graphemes rather than bytes in UTF-8.
bool IsNextMatchWithinSnippetWindow(BreakIterator* bi,
                                    size_t previous_match_end,
                                    size_t next_match_start) {
  // If it's within a window in terms of bytes, it's certain
  // that it's within a window in terms of graphemes as well.
  if (next_match_start < previous_match_end + kSnippetContext)
    return true;
  bi->isBoundary(previous_match_end);
  // An alternative to this is to call |bi->next()| at most
  // kSnippetContext times, compare |bi->current()| with |next_match_start|
  // after each call and return early if possible. There are other
  // heuristics to speed things up if necessary, but it's not likely that
  // we need to bother.
  bi->next(kSnippetContext);
  int64 current = bi->current();
  return (next_match_start < static_cast<uint64>(current) ||
          current == BreakIterator::DONE);
}

}  // namespace

// static
void Snippet::ExtractMatchPositions(const std::string& offsets_str,
                                    const std::string& column_num,
                                    MatchPositions* match_positions) {
  DCHECK(match_positions);
  if (offsets_str.empty())
    return;
  std::vector<std::string> offsets;
  SplitString(offsets_str, ' ', &offsets);
  // SQLite offsets are sets of four integers:
  //   column, query term, match offset, match length
  // Matches within a string are marked by (start, end) pairs.
  for (size_t i = 0; i < offsets.size() - 3; i += 4) {
    if (offsets[i] != column_num)
      continue;
    const size_t start = atoi(offsets[i + 2].c_str());
    const size_t end = start + atoi(offsets[i + 3].c_str());
    // Switch to DCHECK after debugging http://crbug.com/15261.
    CHECK(end >= start);
    AddMatch(start, end, match_positions);
  }
}

// static
void Snippet::ConvertMatchPositionsToWide(
    const std::string& utf8_string,
    Snippet::MatchPositions* match_positions) {
  DCHECK(match_positions);
  int32_t utf8_pos = 0;
  size_t wide_pos = 0;
  const char* utf8_cstring = utf8_string.c_str();
  const int32_t utf8_length = static_cast<int32_t>(utf8_string.size());
  for (Snippet::MatchPositions::iterator i = match_positions->begin();
       i != match_positions->end(); ++i) {
    i->first = AdvanceAndReturnWidePos(utf8_cstring, utf8_length,
                                       i->first, &utf8_pos, &wide_pos);
    i->second = AdvanceAndReturnWidePos(utf8_cstring, utf8_length,
                                        i->second, &utf8_pos, &wide_pos);
  }
}

void Snippet::ComputeSnippet(const MatchPositions& match_positions,
                             const std::string& document) {
  // The length of snippets we try to produce.
  // We can generate longer snippets but stop once we cross kSnippetMaxLength.
  const size_t kSnippetMaxLength = 200;
  const std::wstring kEllipsis = L" ... ";

  UText* document_utext = NULL;
  UErrorCode status = U_ZERO_ERROR;
  document_utext = utext_openUTF8(document_utext, document.data(),
                                  document.size(), &status);
  // Locale does not matter because there's no per-locale customization
  // for character iterator.
  scoped_ptr<BreakIterator> bi(
    BreakIterator::createCharacterInstance(Locale::getDefault(), status));
  bi->setText(document_utext, status);
  DCHECK(U_SUCCESS(status));

  // We build the snippet by iterating through the matches and then grabbing
  // context around each match.  If matches are near enough each other (within
  // kSnippetContext), we skip the "..." between them.
  std::wstring snippet;
  size_t start = 0;
  for (size_t i = 0; i < match_positions.size(); ++i) {
    // Some shorter names for the current match.
    const size_t match_start = match_positions[i].first;
    const size_t match_end = match_positions[i].second;

    // Switch to DCHECK after debugging http://crbug.com/15261.
    CHECK(match_end > match_start);
    CHECK(match_end <= document.size());

    // Add the context, if any, to show before the match.
    size_t context_start = match_start;
    MoveByNGraphemes(bi.get(), -kSnippetContext, &context_start);
    start = std::max(start, context_start);
    if (start < match_start) {
      if (start > 0)
        snippet += kEllipsis;
      // Switch to DCHECK after debugging http://crbug.com/15261.
      CHECK(start < document.size());
      snippet += UTF8ToWide(document.substr(start, match_start - start));
    }

    // Add the match.
    const size_t first = snippet.size();
    snippet += UTF8ToWide(document.substr(match_start,
                                          match_end - match_start));
    matches_.push_back(std::make_pair(first, snippet.size()));

    // Compute the context, if any, to show after the match.
    size_t end;
    // Check if the next match falls within our snippet window.
    if (i + 1 < match_positions.size() &&
        IsNextMatchWithinSnippetWindow(bi.get(), match_end,
            match_positions[i + 1].first)) {
      // Yes, it's within the window.  Make the end context extend just up
      // to the next match.
      end = match_positions[i + 1].first;
      // Switch to DCHECK after debugging http://crbug.com/15261.
      CHECK(end >= match_end);
      CHECK(end <= document.size());
      snippet += UTF8ToWide(document.substr(match_end, end - match_end));
    } else {
      // No, there's either no next match or the next match is too far away.
      end = match_end;
      MoveByNGraphemes(bi.get(), kSnippetContext, &end);
      // Switch to DCHECK after debugging http://crbug.com/15261.
      CHECK(end >= match_end);
      CHECK(end <= document.size());
      snippet += UTF8ToWide(document.substr(match_end, end - match_end));
      if (end < document.size())
        snippet += kEllipsis;
    }
    start = end;

    // Stop here if we have enough snippet computed.
    if (snippet.size() >= kSnippetMaxLength)
      break;
  }

  utext_close(document_utext);
  swap(text_, snippet);
}
<|endoftext|>


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

#ifdef CS_TARGETPLATFORM_WINDOWS

#include <CSBackend/Platform/Windows/Input/Gamepad/GamepadSystem.h>

#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Base/AppConfig.h>
#include <ChilliSource/Core/Base/Screen.h>
#include <ChilliSource/Core/Threading/TaskScheduler.h>
#include <ChilliSource/Core/Delegate/MakeDelegate.h>
#include <ChilliSource/Input/Gamepad/GamepadAxis.h>

#include <CSBackend/Platform/Windows/SFML/Base/SFMLWindow.h>

namespace CSBackend
{
	namespace Windows
	{
		CS_DEFINE_NAMEDTYPE(GamepadSystem);

        //------------------------------------------------------------------------------
		bool GamepadSystem::IsA(ChilliSource::InterfaceIDType interfaceId) const noexcept
		{
			return (ChilliSource::GamepadSystem::InterfaceID == interfaceId || GamepadSystem::InterfaceID == interfaceId);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnInit() noexcept
		{
			SFMLWindow::Get()->SetJoystickDelegates(ChilliSource::MakeDelegate(this, &GamepadSystem::OnJoystickConnected), ChilliSource::MakeDelegate(this, &GamepadSystem::OnJoystickDisconnected),
													ChilliSource::MakeDelegate(this, &GamepadSystem::OnButtonPressed), ChilliSource::MakeDelegate(this, &GamepadSystem::OnButtonReleased),
													ChilliSource::MakeDelegate(this, &GamepadSystem::OnAxisMoved));

			//SFML doesn't notify us about already connected joysticks.
			for(u32 i=0; i<ChilliSource::Gamepad::k_maxGamepads; ++i)
			{
				if(sf::Joystick::isConnected(i))
				{
					OnJoystickConnected(i);
				}
			}
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnJoystickConnected(u32 index) noexcept
		{
			CS_LOG_VERBOSE_FMT("Gamepad Connected: %s\n", sf::Joystick::getIdentification(index).name.toAnsiString().c_str());

			u32 supportedAxisFlags = 0;
			for(u32 i=0; i<=(u32)sf::Joystick::Axis::PovY; ++i)
			{
				if(sf::Joystick::hasAxis(index, (sf::Joystick::Axis)i))
				{
					supportedAxisFlags |= (1u << i);
				}
			}
			m_mapSFMLToCSIds[index] = AddGamepadCreateEvent(sf::Joystick::getIdentification(index).name.toAnsiString(), sf::Joystick::getButtonCount(index), supportedAxisFlags);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnJoystickDisconnected(u32 index) noexcept
		{
			AddGamepadRemoveEvent(m_mapSFMLToCSIds[index]);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnButtonPressed(u32 joystickIndex, u32 buttonIndex) noexcept
		{
			AddButtonPressureChangedEvent(m_mapSFMLToCSIds[joystickIndex], buttonIndex, 1.0f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnButtonReleased(u32 joystickIndex, u32 buttonIndex) noexcept
		{
			AddButtonPressureChangedEvent(m_mapSFMLToCSIds[joystickIndex], buttonIndex, 0.0f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnAxisMoved(u32 joystickIndex, sf::Joystick::Axis axisId, f32 pos) noexcept
		{
			AddAxisPositionChangedEvent(m_mapSFMLToCSIds[joystickIndex], (ChilliSource::GamepadAxis)axisId, pos * 0.01f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnDestroy() noexcept
		{
            SFMLWindow::Get()->RemoveJoystickDelegates();
		}
	}
}

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

#ifdef CS_TARGETPLATFORM_WINDOWS

#include <CSBackend/Platform/Windows/Input/Gamepad/GamepadSystem.h>

#include <ChilliSource/Core/Base/Application.h>
#include <ChilliSource/Core/Base/AppConfig.h>
#include <ChilliSource/Core/Base/Screen.h>
#include <ChilliSource/Core/Threading/TaskScheduler.h>
#include <ChilliSource/Core/Delegate/MakeDelegate.h>
#include <ChilliSource/Input/Gamepad/GamepadAxis.h>

#include <CSBackend/Platform/Windows/SFML/Base/SFMLWindow.h>

namespace CSBackend
{
	namespace Windows
	{
		CS_DEFINE_NAMEDTYPE(GamepadSystem);

        //------------------------------------------------------------------------------
		bool GamepadSystem::IsA(ChilliSource::InterfaceIDType interfaceId) const noexcept
		{
			return (ChilliSource::GamepadSystem::InterfaceID == interfaceId || GamepadSystem::InterfaceID == interfaceId);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnInit() noexcept
		{
			SFMLWindow::Get()->SetJoystickDelegates(ChilliSource::MakeDelegate(this, &GamepadSystem::OnJoystickConnected), ChilliSource::MakeDelegate(this, &GamepadSystem::OnJoystickDisconnected),
													ChilliSource::MakeDelegate(this, &GamepadSystem::OnButtonPressed), ChilliSource::MakeDelegate(this, &GamepadSystem::OnButtonReleased),
													ChilliSource::MakeDelegate(this, &GamepadSystem::OnAxisMoved));

			sf::Joystick::update();
			//SFML doesn't notify us about already connected joysticks.
			for(u32 i=0; i<ChilliSource::Gamepad::k_maxGamepads; ++i)
			{
				if(sf::Joystick::isConnected(i))
				{
					OnJoystickConnected(i);
				}
			}
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnJoystickConnected(u32 index) noexcept
		{
			CS_LOG_VERBOSE_FMT("Gamepad Connected: %s\n", sf::Joystick::getIdentification(index).name.toAnsiString().c_str());

			u32 supportedAxisFlags = 0;
			for(u32 i=0; i<=(u32)sf::Joystick::Axis::PovY; ++i)
			{
				if(sf::Joystick::hasAxis(index, (sf::Joystick::Axis)i))
				{
					supportedAxisFlags |= (1u << i);
				}
			}
			m_mapSFMLToCSIds[index] = AddGamepadCreateEvent(sf::Joystick::getIdentification(index).name.toAnsiString(), sf::Joystick::getButtonCount(index), supportedAxisFlags);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnJoystickDisconnected(u32 index) noexcept
		{
			AddGamepadRemoveEvent(m_mapSFMLToCSIds[index]);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnButtonPressed(u32 joystickIndex, u32 buttonIndex) noexcept
		{
			AddButtonPressureChangedEvent(m_mapSFMLToCSIds[joystickIndex], buttonIndex, 1.0f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnButtonReleased(u32 joystickIndex, u32 buttonIndex) noexcept
		{
			AddButtonPressureChangedEvent(m_mapSFMLToCSIds[joystickIndex], buttonIndex, 0.0f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnAxisMoved(u32 joystickIndex, sf::Joystick::Axis axisId, f32 pos) noexcept
		{
			AddAxisPositionChangedEvent(m_mapSFMLToCSIds[joystickIndex], (ChilliSource::GamepadAxis)axisId, pos * 0.01f);
		}

		//------------------------------------------------------------------------------
		void GamepadSystem::OnDestroy() noexcept
		{
            SFMLWindow::Get()->RemoveJoystickDelegates();
		}
	}
}

#endif
<|endoftext|>


<commit_before>#include "GamePad.h"
#include <cstdio>

namespace
{
	typedef DWORD (*XInputGetStatePointer)(DWORD dwUserIndex, XINPUT_STATE* pState);
	typedef DWORD (*XInputSetStatePointer)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);

	class XInputLoader
	{
	public:
		XInputLoader()
			: mLoaded(false), mHandle(0), mGetState(0), mSetState(0)
		{
		}

		~XInputLoader()
		{
		}

		void ensureLoaded()
		{
			if (!mLoaded)
			{
				mHandle = LoadLibrary("xinput1_3.dll");
				if (mHandle != NULL)
				{
					mGetState = (XInputGetStatePointer)GetProcAddress(mHandle, (LPCSTR)100); // Ordinal 100 is the same as XInputGetState but supports the Guide button.
					mSetState = (XInputSetStatePointer)GetProcAddress(mHandle, "XInputSetState");
					mLoaded = true;
				}
				else
				{
					printf_s("[XInput.NET] Failed to loaded xinput1_3.dll (error code 0x%08x, check that DirectX End-User Runtimes"
						" is installed (http://www.microsoft.com/en-us/download/details.aspx?id=8109)\n", GetLastError());
				}
			}
		}

		XInputGetStatePointer mGetState;
		XInputSetStatePointer mSetState;

	private:
		bool mLoaded;
		HMODULE mHandle;
	};

	XInputLoader gXInputLoader;
}

DWORD XInputGamePadGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
	gXInputLoader.ensureLoaded();
	return gXInputLoader.mGetState(dwUserIndex, pState);
}

void XInputGamePadSetState(DWORD dwUserIndex, float leftMotor, float rightMotor)
{
	gXInputLoader.ensureLoaded();
	XINPUT_VIBRATION vibration = { (int)(leftMotor * 65535), (int)(rightMotor * 65535) };
	gXInputLoader.mSetState(dwUserIndex, &vibration);
}<commit_msg>Look for xinput1_4.dll and xinput9_1_0.dll in case xinput1_3.dll is missing.<commit_after>#include "GamePad.h"
#include <cstdio>

namespace
{
	typedef DWORD (*XInputGetStatePointer)(DWORD dwUserIndex, XINPUT_STATE* pState);
	typedef DWORD (*XInputSetStatePointer)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);

	class XInputLoader
	{
	public:
		XInputLoader()
			: mLoaded(false), mHandle(0), mGetState(0), mSetState(0)
		{
		}

		~XInputLoader()
		{
		}

		void ensureLoaded()
		{
			if (!mLoaded)
			{
				// Keep hold of error codes from each library we try to load.
				DWORD xinput1_3_ErrorCode = 0;
				DWORD xinput1_4_ErrorCode = 0;
				DWORD xinput9_1_ErrorCode = 0;

				// Try XInput 1.3 first as it has all the features we need.
				mHandle = LoadLibrary("xinput1_3.dll");
				xinput1_3_ErrorCode = GetLastError();

				// Look for XInput 1.4 as a backup (newer machines may not have 1.3 at all).
				if(mHandle == NULL)
				{
					mHandle = LoadLibrary("xinput1_4.dll");
					xinput1_4_ErrorCode = GetLastError();
				}

				// Look for XInput 9.1.0 as a last resort! One of the others should exist but we may as well try to load it.
				if(mHandle == NULL)
				{
					mHandle = LoadLibrary("xinput9_1_0.dll");
					xinput9_1_ErrorCode = GetLastError();
				}

				if (mHandle != NULL)
				{
					mGetState = (XInputGetStatePointer)GetProcAddress(mHandle, (LPCSTR)100); // Ordinal 100 is the same as XInputGetState but supports the Guide button.
					mSetState = (XInputSetStatePointer)GetProcAddress(mHandle, "XInputSetState");
					mLoaded = true;
				}
				else
				{
					printf_s("[XInput.NET] Failed to load xinput1_3.dll, xinput1_4.dll and xinput9_1_0.dll (error codes 0x%08x, 0x%08x, 0x%08x respectively; check that \"DirectX End-User Runtimes (June 2010)\""
						" is installed (http://www.microsoft.com/en-us/download/details.aspx?id=8109)\n", xinput1_3_ErrorCode, xinput1_4_ErrorCode, xinput9_1_ErrorCode);
				}
			}
		}

		XInputGetStatePointer mGetState;
		XInputSetStatePointer mSetState;

	private:
		bool mLoaded;
		HMODULE mHandle;
	};

	XInputLoader gXInputLoader;
}

DWORD XInputGamePadGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
	gXInputLoader.ensureLoaded();
	return gXInputLoader.mGetState(dwUserIndex, pState);
}

void XInputGamePadSetState(DWORD dwUserIndex, float leftMotor, float rightMotor)
{
	gXInputLoader.ensureLoaded();
	XINPUT_VIBRATION vibration = { (int)(leftMotor * 65535), (int)(rightMotor * 65535) };
	gXInputLoader.mSetState(dwUserIndex, &vibration);
}<|endoftext|>


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

#include "chrome/browser/ui/views/ssl_client_certificate_selector.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/grit/generated_resources.h"
#include "components/web_modal/popup_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/web_contents.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget.h"

#if defined(USE_NSS)
#include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
#endif

SSLClientCertificateSelector::SSLClientCertificateSelector(
    content::WebContents* web_contents,
    const scoped_refptr<net::SSLCertRequestInfo>& cert_request_info,
    scoped_ptr<content::ClientCertificateDelegate> delegate)
    : CertificateSelector(cert_request_info->client_certs, web_contents),
      SSLClientAuthObserver(web_contents->GetBrowserContext(),
                            cert_request_info,
                            delegate.Pass()) {
  DVLOG(1) << __FUNCTION__;
}

SSLClientCertificateSelector::~SSLClientCertificateSelector() {
}

void SSLClientCertificateSelector::Init() {
  StartObserving();
  InitWithText(l10n_util::GetStringFUTF16(
      IDS_CLIENT_CERT_DIALOG_TEXT,
      base::ASCIIToUTF16(cert_request_info()->host_and_port.ToString())));
}

void SSLClientCertificateSelector::OnCertSelectedByNotification() {
  DVLOG(1) << __FUNCTION__;
  GetWidget()->Close();
}

bool SSLClientCertificateSelector::Cancel() {
  DVLOG(1) << __FUNCTION__;
  StopObserving();
  CertificateSelected(nullptr);
  return true;
}

bool SSLClientCertificateSelector::Accept() {
  DVLOG(1) << __FUNCTION__;
  scoped_refptr<net::X509Certificate> cert = GetSelectedCert();
  if (cert.get()) {
    // Remove the observer before we try unlocking, otherwise we might act on a
    // notification while waiting for the unlock dialog, causing us to delete
    // ourself before the Unlocked callback gets called.
    StopObserving();
#if defined(USE_NSS)
    chrome::UnlockCertSlotIfNecessary(
        cert.get(), chrome::kCryptoModulePasswordClientAuth,
        cert_request_info()->host_and_port, GetWidget()->GetNativeView(),
        base::Bind(&SSLClientCertificateSelector::Unlocked,
                   base::Unretained(this), cert));
#else
    Unlocked(cert.get());
#endif
    return false;  // Unlocked() will close the dialog.
  }

  return false;
}

bool SSLClientCertificateSelector::Close() {
  // By default, closing the dialog calls the Cancel method. However, selecting
  // cancel in the UI currently continues the request with no certificate,
  // remembering the selection. If the dialog is closed by closing the
  // containing tab, the request should abort.
  CancelCertificateSelection();
  return true;
}

void SSLClientCertificateSelector::Unlocked(net::X509Certificate* cert) {
  DVLOG(1) << __FUNCTION__;
  CertificateSelected(cert);
  GetWidget()->Close();
}

namespace chrome {

void ShowSSLClientCertificateSelector(
    content::WebContents* contents,
    net::SSLCertRequestInfo* cert_request_info,
    scoped_ptr<content::ClientCertificateDelegate> delegate) {
  DVLOG(1) << __FUNCTION__ << " " << contents;
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  // Not all WebContentses can show modal dialogs.
  //
  // TODO(davidben): Move this hook to the WebContentsDelegate and only try to
  // show a dialog in Browser's implementation. https://crbug.com/456255
  if (web_modal::PopupManager::FromWebContents(contents) == nullptr)
    return;

  SSLClientCertificateSelector* selector = new SSLClientCertificateSelector(
      contents, cert_request_info, delegate.Pass());
  selector->Init();
  selector->Show();
}

}  // namespace chrome
<commit_msg>Remove DVLOG spam and unnecessary StopObserving calls.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/ssl_client_certificate_selector.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/grit/generated_resources.h"
#include "components/web_modal/popup_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/web_contents.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget.h"

#if defined(USE_NSS)
#include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
#endif

SSLClientCertificateSelector::SSLClientCertificateSelector(
    content::WebContents* web_contents,
    const scoped_refptr<net::SSLCertRequestInfo>& cert_request_info,
    scoped_ptr<content::ClientCertificateDelegate> delegate)
    : CertificateSelector(cert_request_info->client_certs, web_contents),
      SSLClientAuthObserver(web_contents->GetBrowserContext(),
                            cert_request_info,
                            delegate.Pass()) {
}

SSLClientCertificateSelector::~SSLClientCertificateSelector() {
}

void SSLClientCertificateSelector::Init() {
  StartObserving();
  InitWithText(l10n_util::GetStringFUTF16(
      IDS_CLIENT_CERT_DIALOG_TEXT,
      base::ASCIIToUTF16(cert_request_info()->host_and_port.ToString())));
}

void SSLClientCertificateSelector::OnCertSelectedByNotification() {
  GetWidget()->Close();
}

bool SSLClientCertificateSelector::Cancel() {
  CertificateSelected(nullptr);
  return true;
}

bool SSLClientCertificateSelector::Accept() {
  scoped_refptr<net::X509Certificate> cert = GetSelectedCert();
  if (cert.get()) {
    // Remove the observer before we try unlocking, otherwise we might act on a
    // notification while waiting for the unlock dialog, causing us to delete
    // ourself before the Unlocked callback gets called.
    StopObserving();
#if defined(USE_NSS)
    chrome::UnlockCertSlotIfNecessary(
        cert.get(), chrome::kCryptoModulePasswordClientAuth,
        cert_request_info()->host_and_port, GetWidget()->GetNativeView(),
        base::Bind(&SSLClientCertificateSelector::Unlocked,
                   base::Unretained(this), cert));
#else
    Unlocked(cert.get());
#endif
    return false;  // Unlocked() will close the dialog.
  }

  return false;
}

bool SSLClientCertificateSelector::Close() {
  // By default, closing the dialog calls the Cancel method. However, selecting
  // cancel in the UI currently continues the request with no certificate,
  // remembering the selection. If the dialog is closed by closing the
  // containing tab, the request should abort.
  CancelCertificateSelection();
  return true;
}

void SSLClientCertificateSelector::Unlocked(net::X509Certificate* cert) {
  CertificateSelected(cert);
  GetWidget()->Close();
}

namespace chrome {

void ShowSSLClientCertificateSelector(
    content::WebContents* contents,
    net::SSLCertRequestInfo* cert_request_info,
    scoped_ptr<content::ClientCertificateDelegate> delegate) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  // Not all WebContentses can show modal dialogs.
  //
  // TODO(davidben): Move this hook to the WebContentsDelegate and only try to
  // show a dialog in Browser's implementation. https://crbug.com/456255
  if (web_modal::PopupManager::FromWebContents(contents) == nullptr)
    return;

  SSLClientCertificateSelector* selector = new SSLClientCertificateSelector(
      contents, cert_request_info, delegate.Pass());
  selector->Init();
  selector->Show();
}

}  // namespace chrome
<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include <libHierGA/HierGA.hpp>
#include "1maxFitness.hpp"

using namespace std;

int main(void) {
	SelectionStrategy * myStrategy = new TournamentSelection(0.5);

	//GenerationModel * myGenerationModel = new SSGAGeneration(2, myStrategy);
	GenerationModel * myGenerationModel = new ReplacingGAGeneration(myStrategy, 0.5);

	EndCondition * myEndCondition = new FitnessMatchEnd(32);

	FitnessFunction * myFunction = new OneMaxFitness();
	ToStringFunction * myToString = new OneMaxToString();
	CrossoverOperation * myCrossover = new NPointCrossover(2);
	MutationOperation * myMutation = new UniformMutation(0.2);

	FitnessPropagator * myPropagator = new NonPropagator();

	int binaryDigits[] = {0,1};

	GenePool ** baseGenes = (GenePool**)malloc(sizeof(GenePool*)*32);

	for (int i = 0; i < 32; i++) {
		baseGenes[i] = new LibraryNode<int>(binaryDigits, 2);
	}

	Individual * templateIndividual = new Individual(baseGenes, 32, myCrossover, myMutation, myFunction, myToString);

	PopulationNode * topLevelPool = new PopulationNode(64, templateIndividual, 100, 1, myGenerationModel, myEndCondition, myPropagator);

	delete(templateIndividual);

	topLevelPool->run(true);

	delete(topLevelPool);
	for (int i = 0; i < 32; i++) {
		delete(baseGenes[i]);
	}

	delete(myGenerationModel);
	delete(myMutation);
	delete(myCrossover);
	delete(myStrategy);
	delete(myEndCondition);
	delete(myFunction);
	delete(myToString);
	delete(myPropagator);

	free(baseGenes);
}

<commit_msg>[1max]: Use proper argument list for ReplacingGAGeneration<commit_after>#include <cstdio>
#include <iostream>
#include <libHierGA/HierGA.hpp>
#include "1maxFitness.hpp"

using namespace std;

int main(void) {
	SelectionStrategy * myStrategy = new TournamentSelection(0.5);

	//GenerationModel * myGenerationModel = new SSGAGeneration(2, myStrategy);
	GenerationModel * myGenerationModel = new ReplacingGAGeneration(myStrategy);

	EndCondition * myEndCondition = new FitnessMatchEnd(32);

	FitnessFunction * myFunction = new OneMaxFitness();
	ToStringFunction * myToString = new OneMaxToString();
	CrossoverOperation * myCrossover = new NPointCrossover(2);
	MutationOperation * myMutation = new UniformMutation(0.2);

	FitnessPropagator * myPropagator = new NonPropagator();

	int binaryDigits[] = {0,1};

	GenePool ** baseGenes = (GenePool**)malloc(sizeof(GenePool*)*32);

	for (int i = 0; i < 32; i++) {
		baseGenes[i] = new LibraryNode<int>(binaryDigits, 2);
	}

	Individual * templateIndividual = new Individual(baseGenes, 32, myCrossover, myMutation, myFunction, myToString);

	PopulationNode * topLevelPool = new PopulationNode(64, templateIndividual, 100, 1, myGenerationModel, myEndCondition, myPropagator);

	delete(templateIndividual);

	topLevelPool->run(true);

	delete(topLevelPool);
	for (int i = 0; i < 32; i++) {
		delete(baseGenes[i]);
	}

	delete(myGenerationModel);
	delete(myMutation);
	delete(myCrossover);
	delete(myStrategy);
	delete(myEndCondition);
	delete(myFunction);
	delete(myToString);
	delete(myPropagator);

	free(baseGenes);
}

<|endoftext|>


<commit_before>// $Id$

#include <klocale.h>

#include "koexceptions.h"

KOException::KOException(const QString &message)
{
  mMessage = message;
}

KOException::~KOException()
{
}

QString KOException::message()
{
  if (mMessage.isEmpty()) return "KOrganizer Error";
  else return mMessage;
}

KOErrorFormat::KOErrorFormat(ErrorCodeFormat code,const QString &message) :
  KOException(message)
{
  mCode = code;
}

QString KOErrorFormat::message()
{
  QString message = "";

  switch (mCode) {
    case LoadError:
      message = i18n("Load Error");
      break;
    case ParseError:
      message = i18n("Parse Error");
      break;
    case CalVersion1:
      message = i18n("vCalendar Version 1.0 detected");
      break;
    case CalVersion2:
      message = i18n("iCalendar Version 2.0 detected");
      break;
    case Restriction:
      message = i18n("Restriction violation");
    default:
      break;
  }

  if (!mMessage.isEmpty()) message += ": " + mMessage;

  return message;
}

KOErrorFormat::ErrorCodeFormat KOErrorFormat::errorCode()
{
  return mCode;
}
<commit_msg>missing i18n()<commit_after>// $Id$

#include <klocale.h>

#include "koexceptions.h"

KOException::KOException(const QString &message)
{
  mMessage = message;
}

KOException::~KOException()
{
}

QString KOException::message()
{
  if (mMessage.isEmpty()) return i18n("KOrganizer Error");
  else return mMessage;
}

KOErrorFormat::KOErrorFormat(ErrorCodeFormat code,const QString &message) :
  KOException(message)
{
  mCode = code;
}

QString KOErrorFormat::message()
{
  QString message = "";

  switch (mCode) {
    case LoadError:
      message = i18n("Load Error");
      break;
    case ParseError:
      message = i18n("Parse Error");
      break;
    case CalVersion1:
      message = i18n("vCalendar Version 1.0 detected");
      break;
    case CalVersion2:
      message = i18n("iCalendar Version 2.0 detected");
      break;
    case Restriction:
      message = i18n("Restriction violation");
    default:
      break;
  }

  if (!mMessage.isEmpty()) message += ": " + mMessage;

  return message;
}

KOErrorFormat::ErrorCodeFormat KOErrorFormat::errorCode()
{
  return mCode;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "kio_single_subject.h"

#include "mailsubject.h"
#include "kio_proto.h"
#include "stringid.h"

#include <kdebug.h>
#include <klocale.h>
#include <kurl.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <krfcdate.h>

#include <qregexp.h>
#include <q3cstring.h>
#include <qstring.h>
//Added by qt3to4:
#include <QTextStream>

KIO_Single_Subject::KIO_Single_Subject( QObject * parent, const char * name,
		    KURL &kurl, KIO::MetaData &metadata, const KIO_Protocol * protocol, KIO::Slave *& slave,
		    const QString &url, const long size )
		: QObject( parent, name )
{
	_kurl = new KURL( kurl );
	_metadata = new KIO::MetaData( metadata );
	_protocol = protocol;
	_name = new QString( url );
	_size = size;
	_message = new QString;

	init( slave );
}

KIO_Single_Subject::~KIO_Single_Subject( )
{
	if( _job )
		KIO::Scheduler::cancelJob( _job );
	delete _kurl;
	delete _metadata;
	delete _name;
	delete _message;
}

void KIO_Single_Subject::init( KIO::Slave *& slave)
{
	_job = KIO::get( *_kurl, false, false );
	_job->addMetaData( *_metadata );

	connect( _job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	connect( _job, SIGNAL( data         (KIO::Job *, const QByteArray &) ),
	         this, SLOT( slotData(KIO::Job *, const QByteArray &) ) );

	if( _protocol->connectionBased( ) && slave )
		KIO::Scheduler::assignJobToSlave( slave , _job );
	else
		KIO::Scheduler::scheduleJob( _job );

}

void KIO_Single_Subject::parseMail( QString * message, KornMailSubject *subject, bool fullMessage )
{
	QTextStream stream( message, QIODevice::ReadOnly );
	QString line;
	QRegExp rx_sender( "^[fF]rom: " ); //Ex: From: ...
	QRegExp rx_sender_has_name1( "^[fF]rom:\\s*(\\w+[\\w\\s]*)\\<" ); //Ex: From: A name<email@domein.country>
	QRegExp rx_sender_has_name2( "^[fF]rom:\\s*\\\"\\s*(\\w+[\\w\\s]*)\\\""); //Ex: From: "A name"<a@invalid>
	QRegExp rx_subject( "^[sS]ubject: " ); //Ex: Subject: ...
	QRegExp rx_date  ( "^[dD]ate:\\s*(\\w{3},\\s*)?(\\d+)\\s*(\\w{3})\\s*(\\d+)\\s*(\\d+):(\\d+):(\\d+)\\s*([+-])(\\d+)\\s*$");
	bool inheader = true;
	bool firstLine = true;
	while ( ! stream.atEnd() )
	{
		line = stream.readLine();
		if( line.isEmpty() && ! firstLine )
			inheader = false;

		if( firstLine && !line.isEmpty() )
			firstLine = false;

		if( inheader )
		{
			if( rx_sender.search( line ) == 0 )
				if( rx_sender_has_name1.search( line ) == 0 )
					subject->setSender( rx_sender_has_name1.cap( 1 )  );
				else if(rx_sender_has_name2.search( line ) == 0)
					subject->setSender( rx_sender_has_name2.cap( 1 ) );
				else
					subject->setSender( line.remove( rx_sender ) );
			else if( rx_subject.search( line ) == 0 )
				subject->setSubject( line.remove( rx_subject ) );
			else if( rx_date.search( line ) == 0 )
			{
				subject->setDate( KRFCDate::parseDate( line.right( line.length() - 6 )  ) +
				                  KRFCDate::localUTCOffset() * 60 );
			}
		}
	}

	subject->setHeader( *message, fullMessage );
}

void KIO_Single_Subject::slotData( KIO::Job* job, const QByteArray& data )
{
	if( job != _job )
		kdWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;
	if( !data.isEmpty() )
		_message->append( data );
}

//KIO::Scheduler::disconnectSlave missing  if connection stops
void KIO_Single_Subject::slotResult( KIO::Job *job )
{
	if( job != _job )
		kdWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;

	if( job->error() )
	{
		kdWarning() << i18n( "Error when fetching %1: %2" ).arg( *_name ).arg( job->errorString() ) << endl;
	} else {
		KornMailSubject * mailSubject = new KornMailSubject( new KornStringId( *_name ), 0 );
		parseMail( _message, mailSubject, _protocol->fullMessage() );
		mailSubject->setSize( _size );
		emit readSubject( mailSubject );
	}

	_job = 0;

	emit finished( this );
}

#include "kio_single_subject.moc"
<commit_msg>forward port: Date parsing fix from Jose Prieto. Approved by Mart Kelder.<commit_after>/*
 * Copyright (C) 2004, Mart Kelder (mart.kde@hccnet.nl)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "kio_single_subject.h"

#include "mailsubject.h"
#include "kio_proto.h"
#include "stringid.h"

#include <kdebug.h>
#include <klocale.h>
#include <kurl.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <krfcdate.h>

#include <qregexp.h>
#include <q3cstring.h>
#include <qstring.h>
//Added by qt3to4:
#include <QTextStream>

KIO_Single_Subject::KIO_Single_Subject( QObject * parent, const char * name,
		    KURL &kurl, KIO::MetaData &metadata, const KIO_Protocol * protocol, KIO::Slave *& slave,
		    const QString &url, const long size )
		: QObject( parent, name )
{
	_kurl = new KURL( kurl );
	_metadata = new KIO::MetaData( metadata );
	_protocol = protocol;
	_name = new QString( url );
	_size = size;
	_message = new QString;

	init( slave );
}

KIO_Single_Subject::~KIO_Single_Subject( )
{
	if( _job )
		KIO::Scheduler::cancelJob( _job );
	delete _kurl;
	delete _metadata;
	delete _name;
	delete _message;
}

void KIO_Single_Subject::init( KIO::Slave *& slave)
{
	_job = KIO::get( *_kurl, false, false );
	_job->addMetaData( *_metadata );

	connect( _job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	connect( _job, SIGNAL( data         (KIO::Job *, const QByteArray &) ),
	         this, SLOT( slotData(KIO::Job *, const QByteArray &) ) );

	if( _protocol->connectionBased( ) && slave )
		KIO::Scheduler::assignJobToSlave( slave , _job );
	else
		KIO::Scheduler::scheduleJob( _job );

}

void KIO_Single_Subject::parseMail( QString * message, KornMailSubject *subject, bool fullMessage )
{
	QTextStream stream( message, QIODevice::ReadOnly );
	QString line;
	QRegExp rx_sender( "^[fF]rom: " ); //Ex: From: ...
	QRegExp rx_sender_has_name1( "^[fF]rom:\\s*(\\w+[\\w\\s]*)\\<" ); //Ex: From: A name<email@domein.country>
	QRegExp rx_sender_has_name2( "^[fF]rom:\\s*\\\"\\s*(\\w+[\\w\\s]*)\\\""); //Ex: From: "A name"<a@invalid>
	QRegExp rx_subject( "^[sS]ubject: " ); //Ex: Subject: ...
	QRegExp rx_date  ( "^[dD]ate: ");
	bool inheader = true;
	bool firstLine = true;
	while ( ! stream.atEnd() )
	{
		line = stream.readLine();
		if( line.isEmpty() && ! firstLine )
			inheader = false;

		if( firstLine && !line.isEmpty() )
			firstLine = false;

		if( inheader )
		{
			if( rx_sender.search( line ) == 0 )
				if( rx_sender_has_name1.search( line ) == 0 )
					subject->setSender( rx_sender_has_name1.cap( 1 )  );
				else if(rx_sender_has_name2.search( line ) == 0)
					subject->setSender( rx_sender_has_name2.cap( 1 ) );
				else
					subject->setSender( line.remove( rx_sender ) );
			else if( rx_subject.search( line ) == 0 )
				subject->setSubject( line.remove( rx_subject ) );
			else if( rx_date.search( line ) == 0 )
			{
                              subject->setDate( KRFCDate::parseDate( line.right( line.length() - 6 ) ) );
			}
		}
	}

	subject->setHeader( *message, fullMessage );
}

void KIO_Single_Subject::slotData( KIO::Job* job, const QByteArray& data )
{
	if( job != _job )
		kdWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;
	if( !data.isEmpty() )
		_message->append( data );
}

//KIO::Scheduler::disconnectSlave missing  if connection stops
void KIO_Single_Subject::slotResult( KIO::Job *job )
{
	if( job != _job )
		kdWarning() << i18n( "Got invalid job; something strange happened?" ) << endl;

	if( job->error() )
	{
		kdWarning() << i18n( "Error when fetching %1: %2" ).arg( *_name ).arg( job->errorString() ) << endl;
	} else {
		KornMailSubject * mailSubject = new KornMailSubject( new KornStringId( *_name ), 0 );
		parseMail( _message, mailSubject, _protocol->fullMessage() );
		mailSubject->setSize( _size );
		emit readSubject( mailSubject );
	}

	_job = 0;

	emit finished( this );
}

#include "kio_single_subject.moc"
<|endoftext|>