<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/chrome_browser_main_posix.h"

#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>

#include <string>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"

using content::BrowserThread;

namespace {

// See comment in |PreEarlyInitialization()|, where sigaction is called.
void SIGCHLDHandler(int signal) {
}

// The OSX fork() implementation can crash in the child process before
// fork() returns.  In that case, the shutdown pipe will still be
// shared with the parent process.  To prevent child crashes from
// causing parent shutdowns, |g_pipe_pid| is the pid for the process
// which registered |g_shutdown_pipe_write_fd|.
// See <http://crbug.com/175341>.
pid_t g_pipe_pid = -1;
int g_shutdown_pipe_write_fd = -1;
int g_shutdown_pipe_read_fd = -1;

// Common code between SIG{HUP, INT, TERM}Handler.
void GracefulShutdownHandler(int signal) {
  // Reinstall the default handler.  We had one shot at graceful shutdown.
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIG_DFL;
  RAW_CHECK(sigaction(signal, &action, NULL) == 0);

  RAW_CHECK(g_pipe_pid == getpid());
  RAW_CHECK(g_shutdown_pipe_write_fd != -1);
  RAW_CHECK(g_shutdown_pipe_read_fd != -1);
  size_t bytes_written = 0;
  do {
    int rv = HANDLE_EINTR(
        write(g_shutdown_pipe_write_fd,
              reinterpret_cast<const char*>(&signal) + bytes_written,
              sizeof(signal) - bytes_written));
    RAW_CHECK(rv >= 0);
    bytes_written += rv;
  } while (bytes_written < sizeof(signal));
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGHUPHandler(int signal) {
  RAW_CHECK(signal == SIGHUP);
  GracefulShutdownHandler(signal);
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGINTHandler(int signal) {
  RAW_CHECK(signal == SIGINT);
  GracefulShutdownHandler(signal);
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGTERMHandler(int signal) {
  RAW_CHECK(signal == SIGTERM);
  GracefulShutdownHandler(signal);
}

// ExitHandler takes care of servicing an exit (from a signal) at the
// appropriate time. Specifically if we get an exit and have not finished
// session restore we delay the exit. To do otherwise means we're exiting part
// way through startup which causes all sorts of problems.
class ExitHandler : public content::NotificationObserver {
 public:
  // Invokes exit when appropriate.
  static void ExitWhenPossibleOnUIThread();

  // Overridden from content::NotificationObserver:
  void Observe(int type,
               const content::NotificationSource& source,
               const content::NotificationDetails& details) override;

 private:
  ExitHandler();
  ~ExitHandler() override;

  // Does the appropriate call to Exit.
  static void Exit();

  content::NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(ExitHandler);
};

// static
void ExitHandler::ExitWhenPossibleOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  if (SessionRestore::IsRestoringSynchronously()) {
    // ExitHandler takes care of deleting itself.
    new ExitHandler();
  } else {
    Exit();
  }
}

void ExitHandler::Observe(int type,
                          const content::NotificationSource& source,
                          const content::NotificationDetails& details) {
  if (!SessionRestore::IsRestoringSynchronously()) {
    // At this point the message loop may not be running (meaning we haven't
    // gotten through browser startup, but are close). Post the task to at which
    // point the message loop is running.
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::Bind(&ExitHandler::Exit));
    delete this;
  }
}

ExitHandler::ExitHandler() {
  registrar_.Add(
      this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
      content::NotificationService::AllBrowserContextsAndSources());
}

ExitHandler::~ExitHandler() {
}

// static
void ExitHandler::Exit() {
#if defined(OS_CHROMEOS)
  // On ChromeOS, exiting on signal should be always clean.
  chrome::ExitCleanly();
#else
  chrome::AttemptExit();
#endif
}

class ShutdownDetector : public base::PlatformThread::Delegate {
 public:
  explicit ShutdownDetector(int shutdown_fd);

  void ThreadMain() override;

 private:
  const int shutdown_fd_;

  DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
};

ShutdownDetector::ShutdownDetector(int shutdown_fd)
    : shutdown_fd_(shutdown_fd) {
  CHECK_NE(shutdown_fd_, -1);
}

// These functions are used to help us diagnose crash dumps that happen
// during the shutdown process.
NOINLINE void ShutdownFDReadError() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

NOINLINE void ShutdownFDClosedError() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

NOINLINE void ExitPosted() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

void ShutdownDetector::ThreadMain() {
  base::PlatformThread::SetName("CrShutdownDetector");

  int signal;
  size_t bytes_read = 0;
  ssize_t ret;
  do {
    ret = HANDLE_EINTR(
        read(shutdown_fd_,
             reinterpret_cast<char*>(&signal) + bytes_read,
             sizeof(signal) - bytes_read));
    if (ret < 0) {
      NOTREACHED() << "Unexpected error: " << strerror(errno);
      ShutdownFDReadError();
      break;
    } else if (ret == 0) {
      NOTREACHED() << "Unexpected closure of shutdown pipe.";
      ShutdownFDClosedError();
      break;
    }
    bytes_read += ret;
  } while (bytes_read < sizeof(signal));
  VLOG(1) << "Handling shutdown for signal " << signal << ".";
  base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);

  if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
    // Without a UI thread to post the exit task to, there aren't many
    // options.  Raise the signal again.  The default handler will pick it up
    // and cause an ungraceful exit.
    RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
    kill(getpid(), signal);

    // The signal may be handled on another thread.  Give that a chance to
    // happen.
    sleep(3);

    // We really should be dead by now.  For whatever reason, we're not. Exit
    // immediately, with the exit status set to the signal number with bit 8
    // set.  On the systems that we care about, this exit status is what is
    // normally used to indicate an exit by this signal's default handler.
    // This mechanism isn't a de jure standard, but even in the worst case, it
    // should at least result in an immediate exit.
    RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
    _exit(signal | (1 << 7));
  }
  ExitPosted();
}

}  // namespace

// ChromeBrowserMainPartsPosix -------------------------------------------------

ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
    const content::MainFunctionParams& parameters)
    : ChromeBrowserMainParts(parameters) {
}

void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
  ChromeBrowserMainParts::PreEarlyInitialization();

  // We need to accept SIGCHLD, even though our handler is a no-op because
  // otherwise we cannot wait on children. (According to POSIX 2001.)
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIGCHLDHandler;
  CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
}

void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
  ChromeBrowserMainParts::PostMainMessageLoopStart();

  int pipefd[2];
  int ret = pipe(pipefd);
  if (ret < 0) {
    PLOG(DFATAL) << "Failed to create pipe";
  } else {
    g_pipe_pid = getpid();
    g_shutdown_pipe_read_fd = pipefd[0];
    g_shutdown_pipe_write_fd = pipefd[1];
#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
    const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
#else
    // ASan instrumentation and -finstrument-functions (used for keeping the
    // shadow stacks) bloat the stack frames, so we need to increase the stack
    // size to avoid hitting the guard page.
    const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
#endif
    // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
    // if you change this, you'll probably need to change the suppression.
    if (!base::PlatformThread::CreateNonJoinable(
            kShutdownDetectorThreadStackSize,
            new ShutdownDetector(g_shutdown_pipe_read_fd))) {
      LOG(DFATAL) << "Failed to create shutdown detector task.";
    }
  }
  // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
  // it may be called right away after handler is set.

  // If adding to this list of signal handlers, note the new signal probably
  // needs to be reset in child processes. See
  // base/process_util_posix.cc:LaunchProcess.

  // We need to handle SIGTERM, because that is how many POSIX-based distros ask
  // processes to quit gracefully at shutdown time.
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIGTERMHandler;
  CHECK(sigaction(SIGTERM, &action, NULL) == 0);
  // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
  // the browser process is being debugged, GDB will catch the SIGINT first.
  action.sa_handler = SIGINTHandler;
  CHECK(sigaction(SIGINT, &action, NULL) == 0);
  // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
  // distros send SIGHUP, SIGTERM, and then SIGKILL.
  action.sa_handler = SIGHUPHandler;
  CHECK(sigaction(SIGHUP, &action, NULL) == 0);
}

void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
#if defined(OS_CHROMEOS)
  NOTREACHED();  // Should not ever happen on ChromeOS.
#elif defined(OS_MACOSX)
  // Not called on Mac because we load the locale files differently.
  NOTREACHED();
#elif defined(USE_AURA)
  // TODO(port): We may want a views based message dialog here eventually, but
  // for now, crash.
  NOTREACHED();
#else
#error "Need MessageBox implementation."
#endif
}
<commit_msg>Use callback instead of notification service for browser main exit handler<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/chrome_browser_main_posix.h"

#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>

#include <string>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace {

// See comment in |PreEarlyInitialization()|, where sigaction is called.
void SIGCHLDHandler(int signal) {
}

// The OSX fork() implementation can crash in the child process before
// fork() returns.  In that case, the shutdown pipe will still be
// shared with the parent process.  To prevent child crashes from
// causing parent shutdowns, |g_pipe_pid| is the pid for the process
// which registered |g_shutdown_pipe_write_fd|.
// See <http://crbug.com/175341>.
pid_t g_pipe_pid = -1;
int g_shutdown_pipe_write_fd = -1;
int g_shutdown_pipe_read_fd = -1;

// Common code between SIG{HUP, INT, TERM}Handler.
void GracefulShutdownHandler(int signal) {
  // Reinstall the default handler.  We had one shot at graceful shutdown.
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIG_DFL;
  RAW_CHECK(sigaction(signal, &action, NULL) == 0);

  RAW_CHECK(g_pipe_pid == getpid());
  RAW_CHECK(g_shutdown_pipe_write_fd != -1);
  RAW_CHECK(g_shutdown_pipe_read_fd != -1);
  size_t bytes_written = 0;
  do {
    int rv = HANDLE_EINTR(
        write(g_shutdown_pipe_write_fd,
              reinterpret_cast<const char*>(&signal) + bytes_written,
              sizeof(signal) - bytes_written));
    RAW_CHECK(rv >= 0);
    bytes_written += rv;
  } while (bytes_written < sizeof(signal));
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGHUPHandler(int signal) {
  RAW_CHECK(signal == SIGHUP);
  GracefulShutdownHandler(signal);
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGINTHandler(int signal) {
  RAW_CHECK(signal == SIGINT);
  GracefulShutdownHandler(signal);
}

// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGTERMHandler(int signal) {
  RAW_CHECK(signal == SIGTERM);
  GracefulShutdownHandler(signal);
}

// ExitHandler takes care of servicing an exit (from a signal) at the
// appropriate time. Specifically if we get an exit and have not finished
// session restore we delay the exit. To do otherwise means we're exiting part
// way through startup which causes all sorts of problems.
class ExitHandler {
 public:
  // Invokes exit when appropriate.
  static void ExitWhenPossibleOnUIThread();

 private:
  ExitHandler();
  ~ExitHandler();

  // Called when a session restore has finished.
  void OnSessionRestoreDone();

  // Does the appropriate call to Exit.
  static void Exit();

  // Points to the on-session-restored callback that was registered with
  // SessionRestore's callback list. When objects of this class are destroyed,
  // the subscription object's destructor will automatically unregister the
  // callback in SessionRestore, so that the callback list does not contain any
  // obsolete callbacks.
  SessionRestore::CallbackSubscription
      on_session_restored_callback_subscription_;

  DISALLOW_COPY_AND_ASSIGN(ExitHandler);
};

// static
void ExitHandler::ExitWhenPossibleOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  if (SessionRestore::IsRestoringSynchronously()) {
    // ExitHandler takes care of deleting itself.
    new ExitHandler();
  } else {
    Exit();
  }
}

ExitHandler::ExitHandler() {
  on_session_restored_callback_subscription_ =
      SessionRestore::RegisterOnSessionRestoredCallback(
          base::Bind(&ExitHandler::OnSessionRestoreDone,
                     base::Unretained(this)));
}

ExitHandler::~ExitHandler() {
}

void ExitHandler::OnSessionRestoreDone() {
  if (!SessionRestore::IsRestoringSynchronously()) {
    // At this point the message loop may not be running (meaning we haven't
    // gotten through browser startup, but are close). Post the task to at which
    // point the message loop is running.
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::Bind(&ExitHandler::Exit));
    delete this;
  }
}

// static
void ExitHandler::Exit() {
#if defined(OS_CHROMEOS)
  // On ChromeOS, exiting on signal should be always clean.
  chrome::ExitCleanly();
#else
  chrome::AttemptExit();
#endif
}

class ShutdownDetector : public base::PlatformThread::Delegate {
 public:
  explicit ShutdownDetector(int shutdown_fd);

  void ThreadMain() override;

 private:
  const int shutdown_fd_;

  DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
};

ShutdownDetector::ShutdownDetector(int shutdown_fd)
    : shutdown_fd_(shutdown_fd) {
  CHECK_NE(shutdown_fd_, -1);
}

// These functions are used to help us diagnose crash dumps that happen
// during the shutdown process.
NOINLINE void ShutdownFDReadError() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

NOINLINE void ShutdownFDClosedError() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

NOINLINE void ExitPosted() {
  // Ensure function isn't optimized away.
  asm("");
  sleep(UINT_MAX);
}

void ShutdownDetector::ThreadMain() {
  base::PlatformThread::SetName("CrShutdownDetector");

  int signal;
  size_t bytes_read = 0;
  ssize_t ret;
  do {
    ret = HANDLE_EINTR(
        read(shutdown_fd_,
             reinterpret_cast<char*>(&signal) + bytes_read,
             sizeof(signal) - bytes_read));
    if (ret < 0) {
      NOTREACHED() << "Unexpected error: " << strerror(errno);
      ShutdownFDReadError();
      break;
    } else if (ret == 0) {
      NOTREACHED() << "Unexpected closure of shutdown pipe.";
      ShutdownFDClosedError();
      break;
    }
    bytes_read += ret;
  } while (bytes_read < sizeof(signal));
  VLOG(1) << "Handling shutdown for signal " << signal << ".";
  base::Closure task = base::Bind(&ExitHandler::ExitWhenPossibleOnUIThread);

  if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
    // Without a UI thread to post the exit task to, there aren't many
    // options.  Raise the signal again.  The default handler will pick it up
    // and cause an ungraceful exit.
    RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
    kill(getpid(), signal);

    // The signal may be handled on another thread.  Give that a chance to
    // happen.
    sleep(3);

    // We really should be dead by now.  For whatever reason, we're not. Exit
    // immediately, with the exit status set to the signal number with bit 8
    // set.  On the systems that we care about, this exit status is what is
    // normally used to indicate an exit by this signal's default handler.
    // This mechanism isn't a de jure standard, but even in the worst case, it
    // should at least result in an immediate exit.
    RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
    _exit(signal | (1 << 7));
  }
  ExitPosted();
}

}  // namespace

// ChromeBrowserMainPartsPosix -------------------------------------------------

ChromeBrowserMainPartsPosix::ChromeBrowserMainPartsPosix(
    const content::MainFunctionParams& parameters)
    : ChromeBrowserMainParts(parameters) {
}

void ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
  ChromeBrowserMainParts::PreEarlyInitialization();

  // We need to accept SIGCHLD, even though our handler is a no-op because
  // otherwise we cannot wait on children. (According to POSIX 2001.)
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIGCHLDHandler;
  CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
}

void ChromeBrowserMainPartsPosix::PostMainMessageLoopStart() {
  ChromeBrowserMainParts::PostMainMessageLoopStart();

  int pipefd[2];
  int ret = pipe(pipefd);
  if (ret < 0) {
    PLOG(DFATAL) << "Failed to create pipe";
  } else {
    g_pipe_pid = getpid();
    g_shutdown_pipe_read_fd = pipefd[0];
    g_shutdown_pipe_write_fd = pipefd[1];
#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
    const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
#else
    // ASan instrumentation and -finstrument-functions (used for keeping the
    // shadow stacks) bloat the stack frames, so we need to increase the stack
    // size to avoid hitting the guard page.
    const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
#endif
    // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
    // if you change this, you'll probably need to change the suppression.
    if (!base::PlatformThread::CreateNonJoinable(
            kShutdownDetectorThreadStackSize,
            new ShutdownDetector(g_shutdown_pipe_read_fd))) {
      LOG(DFATAL) << "Failed to create shutdown detector task.";
    }
  }
  // Setup signal handlers for shutdown AFTER shutdown pipe is setup because
  // it may be called right away after handler is set.

  // If adding to this list of signal handlers, note the new signal probably
  // needs to be reset in child processes. See
  // base/process_util_posix.cc:LaunchProcess.

  // We need to handle SIGTERM, because that is how many POSIX-based distros ask
  // processes to quit gracefully at shutdown time.
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIGTERMHandler;
  CHECK(sigaction(SIGTERM, &action, NULL) == 0);
  // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
  // the browser process is being debugged, GDB will catch the SIGINT first.
  action.sa_handler = SIGINTHandler;
  CHECK(sigaction(SIGINT, &action, NULL) == 0);
  // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
  // distros send SIGHUP, SIGTERM, and then SIGKILL.
  action.sa_handler = SIGHUPHandler;
  CHECK(sigaction(SIGHUP, &action, NULL) == 0);
}

void ChromeBrowserMainPartsPosix::ShowMissingLocaleMessageBox() {
#if defined(OS_CHROMEOS)
  NOTREACHED();  // Should not ever happen on ChromeOS.
#elif defined(OS_MACOSX)
  // Not called on Mac because we load the locale files differently.
  NOTREACHED();
#elif defined(USE_AURA)
  // TODO(port): We may want a views based message dialog here eventually, but
  // for now, crash.
  NOTREACHED();
#else
#error "Need MessageBox implementation."
#endif
}
<|endoftext|>


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

#include "chrome/browser/chromeos/external_metrics.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "base/basictypes.h"
#include "base/eintr_wrapper.h"
#include "base/metrics/histogram.h"
#include "base/perftimer.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "content/browser/user_metrics.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace chromeos {

// The interval between external metrics collections, in milliseconds.
static const int kExternalMetricsCollectionIntervalMs = 30 * 1000;

ExternalMetrics::ExternalMetrics()
    : test_recorder_(NULL) {
}

ExternalMetrics::~ExternalMetrics() {}

void ExternalMetrics::Start() {
  // Register user actions external to the browser.
  // chrome/tools/extract_actions.py won't understand these lines, so all of
  // these are explicitly added in that script.
  // TODO(derat): We shouldn't need to verify actions before reporting them;
  // remove all of this once http://crosbug.com/11125 is fixed.
  valid_user_actions_.insert("Accel_NextWindow_Tab");
  valid_user_actions_.insert("Accel_PrevWindow_Tab");
  valid_user_actions_.insert("Accel_NextWindow_F5");
  valid_user_actions_.insert("Accel_PrevWindow_F5");
  valid_user_actions_.insert("Accel_BrightnessDown_F6");
  valid_user_actions_.insert("Accel_BrightnessUp_F7");
  valid_user_actions_.insert("Cryptohome.PKCS11InitFail");
  valid_user_actions_.insert("Updater.ServerCertificateChanged");
  valid_user_actions_.insert("Updater.ServerCertificateFailed");

  ScheduleCollector();
}

void ExternalMetrics::RecordActionUI(std::string action_string) {
  if (valid_user_actions_.count(action_string)) {
    UserMetrics::RecordComputedAction(action_string);
  } else {
    LOG(ERROR) << "undefined UMA action: " << action_string;
  }
}

void ExternalMetrics::RecordAction(const char* action) {
  std::string action_string(action);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this, &ExternalMetrics::RecordActionUI, action_string));
}

void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
  if (g_browser_process && g_browser_process->metrics_service()) {
    g_browser_process->metrics_service()->LogChromeOSCrash(crash_kind);
  }
}

void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this, &ExternalMetrics::RecordCrashUI, crash_kind));
}

void ExternalMetrics::RecordHistogram(const char* histogram_data) {
  int sample, min, max, nbuckets;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d %d %d",
                 name, &sample, &min, &max, &nbuckets);
  if (n != 5) {
    LOG(ERROR) << "bad histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::Histogram::FactoryGet(
      name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::RecordLinearHistogram(const char* histogram_data) {
  int sample, max;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d", name, &sample, &max);
  if (n != 3) {
    LOG(ERROR) << "bad linear histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::LinearHistogram::FactoryGet(
      name, 1, max, max + 1, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::CollectEvents() {
  const char* event_file_path = "/var/log/metrics/uma-events";
  struct stat stat_buf;
  int result;
  if (!test_path_.empty()) {
    event_file_path = test_path_.value().c_str();
  }
  result = stat(event_file_path, &stat_buf);
  if (result < 0) {
    if (errno != ENOENT) {
      PLOG(ERROR) << event_file_path << ": bad metrics file stat";
    }
    // Nothing to collect---try later.
    return;
  }
  if (stat_buf.st_size == 0) {
    // Also nothing to collect.
    return;
  }
  int fd = open(event_file_path, O_RDWR);
  if (fd < 0) {
    PLOG(ERROR) << event_file_path << ": cannot open";
    return;
  }
  result = flock(fd, LOCK_EX);
  if (result < 0) {
    PLOG(ERROR) << event_file_path << ": cannot lock";
    close(fd);
    return;
  }
  // This processes all messages in the log.  Each message starts with a 4-byte
  // field containing the length of the entire message.  The length is followed
  // by a name-value pair of null-terminated strings.  When all messages are
  // read and processed, or an error occurs, truncate the file to zero size.
  for (;;) {
    int32 message_size;
    result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message header";
      break;
    }
    if (result == 0) {  // normal EOF
      break;
    }
    if (result < static_cast<int>(sizeof(message_size))) {
      LOG(ERROR) << "bad read size " << result <<
                    ", expecting " << sizeof(message_size);
      break;
    }
    // kMetricsMessageMaxLength applies to the entire message: the 4-byte
    // length field and the two null-terminated strings.
    if (message_size < 2 + static_cast<int>(sizeof(message_size)) ||
        message_size > static_cast<int>(kMetricsMessageMaxLength)) {
      LOG(ERROR) << "bad message size " << message_size;
      break;
    }
    message_size -= sizeof(message_size);  // already read this much
    uint8 buffer[kMetricsMessageMaxLength];
    result = HANDLE_EINTR(read(fd, buffer, message_size));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message body";
      break;
    }
    if (result < message_size) {
      LOG(ERROR) << "message too short: length " << result <<
                    ", expected " << message_size;
      break;
    }
    // The buffer should now contain a pair of null-terminated strings.
    uint8* p = reinterpret_cast<uint8*>(memchr(buffer, '\0', message_size));
    uint8* q = NULL;
    if (p != NULL) {
      q = reinterpret_cast<uint8*>(
        memchr(p + 1, '\0', message_size - (p + 1 - buffer)));
    }
    if (q == NULL) {
      LOG(ERROR) << "bad name-value pair for metrics";
      break;
    } else {
      char* name = reinterpret_cast<char*>(buffer);
      char* value = reinterpret_cast<char*>(p + 1);
      if (test_recorder_ != NULL) {
        test_recorder_(name, value);
      } else if (strcmp(name, "crash") == 0) {
        RecordCrash(value);
      } else if (strcmp(name, "histogram") == 0) {
        RecordHistogram(value);
      } else if (strcmp(name, "linearhistogram") == 0) {
        RecordLinearHistogram(value);
      } else if (strcmp(name, "useraction") == 0) {
        RecordAction(value);
      } else {
        LOG(ERROR) << "invalid event type: " << name;
      }
    }
  }

  result = ftruncate(fd, 0);
  if (result < 0) {
    PLOG(ERROR) << "truncate metrics log";
  }
  result = flock(fd, LOCK_UN);
  if (result < 0) {
    PLOG(ERROR) << "unlock metrics log";
  }
  result = close(fd);
  if (result < 0) {
    PLOG(ERROR) << "close metrics log";
  }
}

void ExternalMetrics::CollectEventsAndReschedule() {
  PerfTimer timer;
  CollectEvents();
  UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
  ScheduleCollector();
}

void ExternalMetrics::ScheduleCollector() {
  bool result;
  result = BrowserThread::PostDelayedTask(
    BrowserThread::FILE, FROM_HERE, NewRunnableMethod(
        this, &chromeos::ExternalMetrics::CollectEventsAndReschedule),
    kExternalMetricsCollectionIntervalMs);
  DCHECK(result);
}

}  // namespace chromeos
<commit_msg>Replace NewRunnableMethod with Bind in ExternalMetrics.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/external_metrics.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>

#include "base/bind.h"
#include "base/basictypes.h"
#include "base/eintr_wrapper.h"
#include "base/metrics/histogram.h"
#include "base/perftimer.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "content/browser/user_metrics.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace chromeos {

// The interval between external metrics collections, in milliseconds.
static const int kExternalMetricsCollectionIntervalMs = 30 * 1000;

ExternalMetrics::ExternalMetrics()
    : test_recorder_(NULL) {
}

ExternalMetrics::~ExternalMetrics() {}

void ExternalMetrics::Start() {
  // Register user actions external to the browser.
  // chrome/tools/extract_actions.py won't understand these lines, so all of
  // these are explicitly added in that script.
  // TODO(derat): We shouldn't need to verify actions before reporting them;
  // remove all of this once http://crosbug.com/11125 is fixed.
  valid_user_actions_.insert("Accel_NextWindow_Tab");
  valid_user_actions_.insert("Accel_PrevWindow_Tab");
  valid_user_actions_.insert("Accel_NextWindow_F5");
  valid_user_actions_.insert("Accel_PrevWindow_F5");
  valid_user_actions_.insert("Accel_BrightnessDown_F6");
  valid_user_actions_.insert("Accel_BrightnessUp_F7");
  valid_user_actions_.insert("Cryptohome.PKCS11InitFail");
  valid_user_actions_.insert("Updater.ServerCertificateChanged");
  valid_user_actions_.insert("Updater.ServerCertificateFailed");

  ScheduleCollector();
}

void ExternalMetrics::RecordActionUI(std::string action_string) {
  if (valid_user_actions_.count(action_string)) {
    UserMetrics::RecordComputedAction(action_string);
  } else {
    LOG(ERROR) << "undefined UMA action: " << action_string;
  }
}

void ExternalMetrics::RecordAction(const char* action) {
  std::string action_string(action);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordActionUI, this, action_string));
}

void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
  if (g_browser_process && g_browser_process->metrics_service()) {
    g_browser_process->metrics_service()->LogChromeOSCrash(crash_kind);
  }
}

void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordCrashUI, this, crash_kind));
}

void ExternalMetrics::RecordHistogram(const char* histogram_data) {
  int sample, min, max, nbuckets;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d %d %d",
                 name, &sample, &min, &max, &nbuckets);
  if (n != 5) {
    LOG(ERROR) << "bad histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::Histogram::FactoryGet(
      name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::RecordLinearHistogram(const char* histogram_data) {
  int sample, max;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d", name, &sample, &max);
  if (n != 3) {
    LOG(ERROR) << "bad linear histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::LinearHistogram::FactoryGet(
      name, 1, max, max + 1, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::CollectEvents() {
  const char* event_file_path = "/var/log/metrics/uma-events";
  struct stat stat_buf;
  int result;
  if (!test_path_.empty()) {
    event_file_path = test_path_.value().c_str();
  }
  result = stat(event_file_path, &stat_buf);
  if (result < 0) {
    if (errno != ENOENT) {
      PLOG(ERROR) << event_file_path << ": bad metrics file stat";
    }
    // Nothing to collect---try later.
    return;
  }
  if (stat_buf.st_size == 0) {
    // Also nothing to collect.
    return;
  }
  int fd = open(event_file_path, O_RDWR);
  if (fd < 0) {
    PLOG(ERROR) << event_file_path << ": cannot open";
    return;
  }
  result = flock(fd, LOCK_EX);
  if (result < 0) {
    PLOG(ERROR) << event_file_path << ": cannot lock";
    close(fd);
    return;
  }
  // This processes all messages in the log.  Each message starts with a 4-byte
  // field containing the length of the entire message.  The length is followed
  // by a name-value pair of null-terminated strings.  When all messages are
  // read and processed, or an error occurs, truncate the file to zero size.
  for (;;) {
    int32 message_size;
    result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message header";
      break;
    }
    if (result == 0) {  // normal EOF
      break;
    }
    if (result < static_cast<int>(sizeof(message_size))) {
      LOG(ERROR) << "bad read size " << result <<
                    ", expecting " << sizeof(message_size);
      break;
    }
    // kMetricsMessageMaxLength applies to the entire message: the 4-byte
    // length field and the two null-terminated strings.
    if (message_size < 2 + static_cast<int>(sizeof(message_size)) ||
        message_size > static_cast<int>(kMetricsMessageMaxLength)) {
      LOG(ERROR) << "bad message size " << message_size;
      break;
    }
    message_size -= sizeof(message_size);  // already read this much
    uint8 buffer[kMetricsMessageMaxLength];
    result = HANDLE_EINTR(read(fd, buffer, message_size));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message body";
      break;
    }
    if (result < message_size) {
      LOG(ERROR) << "message too short: length " << result <<
                    ", expected " << message_size;
      break;
    }
    // The buffer should now contain a pair of null-terminated strings.
    uint8* p = reinterpret_cast<uint8*>(memchr(buffer, '\0', message_size));
    uint8* q = NULL;
    if (p != NULL) {
      q = reinterpret_cast<uint8*>(
        memchr(p + 1, '\0', message_size - (p + 1 - buffer)));
    }
    if (q == NULL) {
      LOG(ERROR) << "bad name-value pair for metrics";
      break;
    } else {
      char* name = reinterpret_cast<char*>(buffer);
      char* value = reinterpret_cast<char*>(p + 1);
      if (test_recorder_ != NULL) {
        test_recorder_(name, value);
      } else if (strcmp(name, "crash") == 0) {
        RecordCrash(value);
      } else if (strcmp(name, "histogram") == 0) {
        RecordHistogram(value);
      } else if (strcmp(name, "linearhistogram") == 0) {
        RecordLinearHistogram(value);
      } else if (strcmp(name, "useraction") == 0) {
        RecordAction(value);
      } else {
        LOG(ERROR) << "invalid event type: " << name;
      }
    }
  }

  result = ftruncate(fd, 0);
  if (result < 0) {
    PLOG(ERROR) << "truncate metrics log";
  }
  result = flock(fd, LOCK_UN);
  if (result < 0) {
    PLOG(ERROR) << "unlock metrics log";
  }
  result = close(fd);
  if (result < 0) {
    PLOG(ERROR) << "close metrics log";
  }
}

void ExternalMetrics::CollectEventsAndReschedule() {
  PerfTimer timer;
  CollectEvents();
  UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
  ScheduleCollector();
}

void ExternalMetrics::ScheduleCollector() {
  bool result;
  result = BrowserThread::PostDelayedTask(
    BrowserThread::FILE, FROM_HERE,
    base::Bind(&chromeos::ExternalMetrics::CollectEventsAndReschedule, this),
    kExternalMetricsCollectionIntervalMs);
  DCHECK(result);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>

#include <unistd.h> // for 'getopt'

//*************************** User Include Files ****************************

#include "Args.h"
#include <lib/support/String.h>
#include <lib/support/Trace.h>

//*************************** Forward Declarations **************************

using std::cerr;
using std::endl;

//***************************************************************************

const char* hpctoolsVerInfo=
#include <include/HPCToolkitVersionInfo.h>

void Args::Version()
{
  cerr << cmd << ": " << hpctoolsVerInfo << endl;
}

void Args::Usage()
{
  cerr
    << "Usage: " << endl
    << "  " << cmd << " [-l | -L]  <binary> <profile>\n"
    << "  " << cmd << " [-V] [ [-M <mlist> -M...] [-X <xlist> -X...] [-R] ] <binary> <profile>\n"

    << endl;
  cerr
    << "Converts various types of profile output into the PROFILE format,\n"
    << "which, in particular, associates source file line information from\n"
    << "<binary> with profile data from <profile>. In effect, the output is\n"
    << "a [source-line -> PC-profile-data] map represented as a XML scope\n"
    << "tree (e.g. file, procedure, statement).  Output is sent to stdout.\n"
    << "\n"
    << "By default, xprof determines a set of metrics available for the\n"
    << "given profile data and includes all of them in the PROFILE output.\n"
    << "\n"
#if 0  // FIXME '[-m <bloop-pcmap>]'
    << "If no <bloop-pcmap> -- a map extended with analysis information\n"
    << "from 'bloop' -- is provided, the program attempts to construct\n"
    << "the PROFILE by querying the <binary>'s debugging information.\n"
    << "Because of the better analysis ability of 'bloop', a <bloop-pcmap>\n"
    << "usually improves the accuracy of the PROFILE.  Moreover, because\n"
    << "no loop recovery is performed, providing <bloop-pcmap> enables\n"
    << "the PROFILE to represent loop nesting information.\n"
    << "[*Not fully implemented.*]\n"
    << "\n"
    << "  -m: specify <bloop-pcmap>\n"
#endif
    << "The following <profile> formats are currently supported: \n"
    << "  - DEC/Compaq/HP's DCPI 'dcpicat' (including ProfileMe) \n"
    << "\n"
    << "Listing available metrics:\n"
    << "  -l       List all derived metrics, in compact form, available from\n"
    << "           <profile> and suppress generation of PROFILE output.\n"
    << "           Note that this output can be used with the -M option.\n"
    << "  -L       List all derived metrics, in long form, available from\n"
    << "           <profile> and suppress generation of PROFILE output.\n"
    << "\n"
    << "Normal Mode:\n"
    << "  -V       Print version information.\n"
    << "  -M mlist Optional colon-separated metric inclusion list. Replaces\n"
    << "           the default metric list. Metrics in PROFILE output will.\n"
    << "           follow this ordering.  Duplicates are allowed (though\n"
    << "           not recommended).\n"
    << "  -X xlist Optional colon-separated metric exclusion list. Excludes\n"
    << "           the listed metrics from either the default metric list or\n"
    << "           the list specified with -M.\n"
    << "  -R       (Most will not find this useful.) For some profile data,\n"
    << "           such as DCPI's ProfileMe, the default is to output derived\n"
    << "           metrics, not the underlying raw metrics; this option\n"
    << "           forces output of only the raw metrics.  Should not be\n"
    << "           used with -M or -X.\n"
    << endl;
}

Args::Args(int argc, char* const* argv)
{
  cmd = argv[0];

  bool printVersion = false;
  listAvailableMetrics = 0; // 0: no, 1: short, 2: long
  outputRawMetrics = false;

  extern char *optarg;
  extern int optind;
  bool error = false;
  trace = 0;
  int c;
  while ((c = getopt(argc, argv, "Vm:lLM:X:Rd")) != EOF) {
    switch (c) {
    case 'V': {
      printVersion = true;
      break;
    }
    case 'm': {
      // A non-null value of 'pcMapFile' indicates it has been set
      if (optarg == NULL) { error = true; }
      pcMapFile = optarg;
      break;
    }

    case 'l': {
      listAvailableMetrics = 1;
      break;
    }
    case 'L': {
      listAvailableMetrics = 2;
      break;
    }

    case 'M': { // may occur multiple times
      if (optarg == NULL) { error = true; }
      if (!metricList.Empty()) { metricList += ":"; }
      metricList += optarg;
      break;
    }
    case 'X': { // may occur multiple times
      if (optarg == NULL) { error = true; }
      if (!excludeMList.Empty()) { excludeMList += ":"; }
      excludeMList += optarg;
      break;
    }
    case 'R': {
      outputRawMetrics = true;
      break;
    }

    case 'd': { // debug
      trace++;
      break;
    }
    case ':':
    case '?': { // error
      error = true;
      break;
    }
    }
  }

  error = error || (optind != argc-2);
  if (!error) {
    progFile = argv[optind];
    profFile = argv[optind+1];
  }

  // Sanity check: -M,-X and -R should not be used at the same time
  if ( (!metricList.Empty() || !excludeMList.Empty()) && outputRawMetrics) {
    cerr << "Error: -M or -X cannot be used with -R.\n";
    error = true;
  }

  IFTRACE << "Args.cmd= " << cmd << endl;
  IFTRACE << "Args.progFile= " << progFile << endl;
  IFTRACE << "Args.profFile= " << profFile << endl;
  IFTRACE << "Args.pcMapFile= " << pcMapFile << endl;
  IFTRACE << "::trace " << ::trace << endl;

  if (printVersion) {
    Version();
    exit(1);
  }

  if (error) {
    Usage();
    exit(1);
  }
}

<commit_msg>Tweak documentation for -M and -X<commit_after>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>

#include <unistd.h> // for 'getopt'

//*************************** User Include Files ****************************

#include "Args.h"
#include <lib/support/String.h>
#include <lib/support/Trace.h>

//*************************** Forward Declarations **************************

using std::cerr;
using std::endl;

//***************************************************************************

const char* hpctoolsVerInfo=
#include <include/HPCToolkitVersionInfo.h>

void Args::Version()
{
  cerr << cmd << ": " << hpctoolsVerInfo << endl;
}

void Args::Usage()
{
  cerr
    << "Usage: " << endl
    << "  " << cmd << " [-l | -L]  <binary> <profile>\n"
    << "  " << cmd << " [-V] [ [-M <mlist> -M...] [-X <xlist> -X...] [-R] ] <binary> <profile>\n"

    << endl;
  cerr
    << "Converts various types of profile output into the PROFILE format,\n"
    << "which, in particular, associates source file line information from\n"
    << "<binary> with profile data from <profile>. In effect, the output is\n"
    << "a [source-line -> PC-profile-data] map represented as a XML scope\n"
    << "tree (e.g. file, procedure, statement).  Output is sent to stdout.\n"
    << "\n"
    << "By default, xprof determines a set of metrics available for the\n"
    << "given profile data and includes all of them in the PROFILE output.\n"
    << "\n"
#if 0  // FIXME '[-m <bloop-pcmap>]'
    << "If no <bloop-pcmap> -- a map extended with analysis information\n"
    << "from 'bloop' -- is provided, the program attempts to construct\n"
    << "the PROFILE by querying the <binary>'s debugging information.\n"
    << "Because of the better analysis ability of 'bloop', a <bloop-pcmap>\n"
    << "usually improves the accuracy of the PROFILE.  Moreover, because\n"
    << "no loop recovery is performed, providing <bloop-pcmap> enables\n"
    << "the PROFILE to represent loop nesting information.\n"
    << "[*Not fully implemented.*]\n"
    << "\n"
    << "  -m: specify <bloop-pcmap>\n"
#endif
    << "The following <profile> formats are currently supported: \n"
    << "  - DEC/Compaq/HP's DCPI 'dcpicat' (including ProfileMe) \n"
    << "\n"
    << "Listing available metrics:\n"
    << "  -l       List all derived metrics, in compact form, available from\n"
    << "           <profile> and suppress generation of PROFILE output.\n"
    << "           Note that this output can be used with the -M option.\n"
    << "  -L       List all derived metrics, in long form, available from\n"
    << "           <profile> and suppress generation of PROFILE output.\n"
    << "\n"
    << "Normal Mode:\n"
    << "  -V       Print version information.\n"
    << "  -M mlist Specify metrics to replace the default metric list.\n"
    << "           Metrics in PROFILE output will follow this ordering.\n"
    << "           <mlist> is a colon-separated list; duplicates are allowed\n"
    << "           (though not recommended).\n"
    << "  -X xlist Specify metrics to exclude from the default metric list\n"
    << "           or from those specified with -M.  <xlist> is a colon-\n"
    << "           separated list.\n"
    << "  -R       (Most will not find this useful.) For some profile data,\n"
    << "           such as DCPI's ProfileMe, the default is to output derived\n"
    << "           metrics, not the underlying raw metrics; this option\n"
    << "           forces output of only the raw metrics.  Should not be\n"
    << "           used with -M or -X.\n"
    << endl;
}

Args::Args(int argc, char* const* argv)
{
  cmd = argv[0];

  bool printVersion = false;
  listAvailableMetrics = 0; // 0: no, 1: short, 2: long
  outputRawMetrics = false;

  extern char *optarg;
  extern int optind;
  bool error = false;
  trace = 0;
  int c;
  while ((c = getopt(argc, argv, "Vm:lLM:X:Rd")) != EOF) {
    switch (c) {
    case 'V': {
      printVersion = true;
      break;
    }
    case 'm': {
      // A non-null value of 'pcMapFile' indicates it has been set
      if (optarg == NULL) { error = true; }
      pcMapFile = optarg;
      break;
    }

    case 'l': {
      listAvailableMetrics = 1;
      break;
    }
    case 'L': {
      listAvailableMetrics = 2;
      break;
    }

    case 'M': { // may occur multiple times
      if (optarg == NULL) { error = true; }
      if (!metricList.Empty()) { metricList += ":"; }
      metricList += optarg;
      break;
    }
    case 'X': { // may occur multiple times
      if (optarg == NULL) { error = true; }
      if (!excludeMList.Empty()) { excludeMList += ":"; }
      excludeMList += optarg;
      break;
    }
    case 'R': {
      outputRawMetrics = true;
      break;
    }

    case 'd': { // debug
      trace++;
      break;
    }
    case ':':
    case '?': { // error
      error = true;
      break;
    }
    }
  }

  error = error || (optind != argc-2);
  if (!error) {
    progFile = argv[optind];
    profFile = argv[optind+1];
  }

  // Sanity check: -M,-X and -R should not be used at the same time
  if ( (!metricList.Empty() || !excludeMList.Empty()) && outputRawMetrics) {
    cerr << "Error: -M or -X cannot be used with -R.\n";
    error = true;
  }

  IFTRACE << "Args.cmd= " << cmd << endl;
  IFTRACE << "Args.progFile= " << progFile << endl;
  IFTRACE << "Args.profFile= " << profFile << endl;
  IFTRACE << "Args.pcMapFile= " << pcMapFile << endl;
  IFTRACE << "::trace " << ::trace << endl;

  if (printVersion) {
    Version();
    exit(1);
  }

  if (error) {
    Usage();
    exit(1);
  }
}

<|endoftext|>


<commit_before>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

****************************************************************************/

#include <unistd.h>

#include "httpclient.h"

#include <QtSql>

#include "httpserver.h"
#include "global.h"

HttpClient::HttpClient(int sockfd, HttpServer *server, QObject *parent) :
    QObject(parent)
{
    m_server = server;
    m_socket = new QTcpSocket(this);
    if (!m_socket->setSocketDescriptor(sockfd)) {
        emit error(m_socket->error());
        return;
    }

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient()));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(discardClient()));
}

void HttpClient::readClient()
{
    if (m_socket->canReadLine()) {
        QByteArray bytesRead = m_socket->readLine();
        QStringList tokens = QString(bytesRead).split(QRegExp("[ \r\n][ \r\n]*"));

        while(m_socket->canReadLine()) {
            bytesRead = m_socket->readLine();
            QList<QByteArray> lineTokens = bytesRead.split(':');
            if (lineTokens.size() == 2) {
                m_request.insert(lineTokens[0], lineTokens[1].trimmed().replace("\r\n",""));
            }
        }

        if (tokens[0] == "GET") {
            m_get = tokens[1];
            if (m_get.startsWith("/video"))
                readVideoRequest();
            else if(m_get.startsWith("/music"))
                readMusicRequest();
            else if(m_get.startsWith("/picture"))
                readPictureRequest();
        }

    }

    m_socket->close();
    discardClient();

    return;
}

void HttpClient::discardClient()
{
    m_file.close();

    m_socket->deleteLater();
    emit disconnected();
}

void HttpClient::readVideoRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("video", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("video", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readMusicRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("music", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("music", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readPictureRequest()
{
}

void HttpClient::answerOk(qint64 length)
{
    QByteArray answer;
    answer += "HTTP/1.1 200 OK \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(length) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

void HttpClient::answerNotFound()
{
    QByteArray answer;
    answer += "HTTP/1.1 404 Not Found \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Connection: close \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

QUrl HttpClient::getMediaUrl(QString mediaType, int id, QString field)
{
    QSqlQuery query(QSqlDatabase::database(DEFAULT_DATABASE_CONNECTION_NAME));
    query.setForwardOnly(true);

    QString queryString;
    queryString.append("SELECT * FROM " + mediaType);
    queryString.append(" WHERE id = " + QString::number(id) + "");
    query.prepare(queryString);

    if (!query.exec()) {
        qWarning("Error executing query: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    // we should have just one result set
    if (!query.next()) {
        qWarning("No records found: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    return QUrl::fromEncoded(query.record().value(field).toByteArray());
}

bool HttpClient::sendFile(QString fileName)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);
    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    answerOk(m_file.size());

    QByteArray ba;
    ba.resize(chunk);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    return  true;
}

bool HttpClient::sendPartial(QString fileName, qint64 offset)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);

    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    QByteArray ba;
    ba.resize(chunk);
    if (!m_file.seek(offset)) {
        qDebug() << "could not seek to offset";
        return false;
    }

    QByteArray answer = "";
    answer += "HTTP/1.1 206 Partial content \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(m_file.size()-offset) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Range: bytes " + QString::number(offset) + "-" + QString::number(m_file.size()-1) + "/" + QString::number(m_file.size()) + " \t\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    return  true;
}
<commit_msg>fixing picture-http-request<commit_after>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

****************************************************************************/

#include <unistd.h>

#include "httpclient.h"

#include <QtSql>

#include "httpserver.h"
#include "global.h"

HttpClient::HttpClient(int sockfd, HttpServer *server, QObject *parent) :
    QObject(parent)
{
    m_server = server;
    m_socket = new QTcpSocket(this);
    if (!m_socket->setSocketDescriptor(sockfd)) {
        emit error(m_socket->error());
        return;
    }

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient()));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(discardClient()));
}

void HttpClient::readClient()
{
    if (m_socket->canReadLine()) {
        QByteArray bytesRead = m_socket->readLine();
        QStringList tokens = QString(bytesRead).split(QRegExp("[ \r\n][ \r\n]*"));

        while(m_socket->canReadLine()) {
            bytesRead = m_socket->readLine();
            QList<QByteArray> lineTokens = bytesRead.split(':');
            if (lineTokens.size() == 2) {
                m_request.insert(lineTokens[0], lineTokens[1].trimmed().replace("\r\n",""));
            }
        }

        if (tokens[0] == "GET") {
            m_get = tokens[1];
            if (m_get.startsWith("/video"))
                readVideoRequest();
            else if(m_get.startsWith("/music"))
                readMusicRequest();
            else if(m_get.startsWith("/picture"))
                readPictureRequest();
        }

    }

    m_socket->close();
    discardClient();

    return;
}

void HttpClient::discardClient()
{
    m_file.close();

    m_socket->deleteLater();
    emit disconnected();
}

void HttpClient::readVideoRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("video", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("video", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readMusicRequest()
{
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);

    if (m_request.contains("Range")) {
        QString offsetString = m_request.value("Range");
        offsetString.remove(0, 6);
        qint64 offset = offsetString.split("-").at(0).toLongLong();
        sendPartial(getMediaUrl("music", id.toInt()).toLocalFile(), offset);
    } else {
        sendFile(getMediaUrl("music", id.toInt()).toLocalFile());
    }

    m_socket->close();
}

void HttpClient::readPictureRequest()
{
    // TODO add thumbnail option
    QString id = m_get.right(m_get.length()-m_get.lastIndexOf("/")-1);
    sendFile(getMediaUrl("picture", id.toInt(), "filepath").toString());
    m_socket->close();
}

void HttpClient::answerOk(qint64 length)
{
    QByteArray answer;
    answer += "HTTP/1.1 200 OK \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(length) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

void HttpClient::answerNotFound()
{
    QByteArray answer;
    answer += "HTTP/1.1 404 Not Found \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Connection: close \r\n";
    answer += "\r\n";

    m_socket->write(answer);
    m_socket->waitForBytesWritten();
}

QUrl HttpClient::getMediaUrl(QString mediaType, int id, QString field)
{
    QSqlQuery query(QSqlDatabase::database(DEFAULT_DATABASE_CONNECTION_NAME));
    query.setForwardOnly(true);

    QString queryString;
    queryString.append("SELECT * FROM " + mediaType);
    queryString.append(" WHERE id = " + QString::number(id) + "");
    query.prepare(queryString);

    if (!query.exec()) {
        qWarning("Error executing query: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    // we should have just one result set
    if (!query.next()) {
        qWarning("No records found: %s", qPrintable(query.lastQuery()));
        return QUrl();
    }

    return QUrl(query.record().value(field).toByteArray());
}

bool HttpClient::sendFile(QString fileName)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);
    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    answerOk(m_file.size());

    QByteArray ba;
    ba.resize(chunk);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    return  true;
}

bool HttpClient::sendPartial(QString fileName, qint64 offset)
{
    int chunk = 1024*16;

    m_file.setFileName(fileName);
    m_file.open(QIODevice::ReadOnly);

    if (!m_file.isOpen()) {
        qDebug() << "could not open file" << m_file.fileName();
        answerNotFound();
        return false;
    }

    QByteArray ba;
    ba.resize(chunk);
    if (!m_file.seek(offset)) {
        qDebug() << "could not seek to offset";
        return false;
    }

    QByteArray answer = "";
    answer += "HTTP/1.1 206 Partial content \r\n";
    answer += "Server: QtMediaHub (Unix) \r\n";
    answer += "Content-Length: " + QString::number(m_file.size()-offset) +"\r\n";
    answer += "Connection: close \r\n";
    answer += "Content-Range: bytes " + QString::number(offset) + "-" + QString::number(m_file.size()-1) + "/" + QString::number(m_file.size()) + " \t\n";
    answer += "Content-Type: application/octet-stream \r\n";
    answer += "Accept-Ranges: bytes \r\n";
    answer += "\r\n";

    m_socket->write(answer);

    while (m_file.read(ba.data(), chunk) && m_socket->state() == QAbstractSocket::ConnectedState) {
        m_socket->write(ba);
        m_socket->waitForBytesWritten();
        sleep(0.1);
    }

    return  true;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX
#define INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX

#include <vcl/dllapi.h>

class GlyphCache;
class GlyphMetric;
class GlyphData;
class ServerFont;
class GlyphCachePeer;
class ServerFontLayoutEngine;
class ServerFontLayout;
class ImplFontOptions;

#include <tools/gen.hxx>
#include <basebmp/bitmapdevice.hxx>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>

namespace basegfx { class B2DPolyPolygon; }

class RawBitmap;

#include <outfont.hxx>
#include <impfont.hxx>

class ServerFontLayout;
#include <sallayout.hxx>

#include <config_graphite.h>
#if ENABLE_GRAPHITE
class GraphiteFaceWrapper;
#endif

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

namespace vcl
{
    struct FontCapabilities;
}

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

class VCL_DLLPUBLIC GlyphCache
{
public:
    explicit                    GlyphCache( GlyphCachePeer& );
    /*virtual*/                 ~GlyphCache();

    static GlyphCache&      GetInstance();

    void                        AddFontFile( const OString& rNormalizedName,
                                    int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes&);
    void                        AnnounceFonts( ImplDevFontList* ) const;

    ServerFont*                 CacheFont( const FontSelectPattern& );
    void                        UncacheFont( ServerFont& );
    void                        ClearFontCache();
    void                        InvalidateAllGlyphs();

protected:
    GlyphCachePeer&             mrPeer;

private:
    friend class ServerFont;
    // used by ServerFont class only
    void                        AddedGlyph( ServerFont&, GlyphData& );
    void                        RemovingGlyph( GlyphData& );
    void                        UsingGlyph( ServerFont&, GlyphData& );
    void                        GrowNotify();

private:
    void                        GarbageCollect();

    // the GlyphCache's FontList matches a font request to a serverfont instance
    // the FontList key's mpFontData member is reinterpreted as integer font id
    struct IFSD_Equal{  bool operator()( const FontSelectPattern&, const FontSelectPattern& ) const; };
    struct IFSD_Hash{ size_t operator()( const FontSelectPattern& ) const; };
    typedef ::boost::unordered_map<FontSelectPattern,ServerFont*,IFSD_Hash,IFSD_Equal > FontList;
    FontList                    maFontList;
    sal_uLong                       mnMaxSize;      // max overall cache size in bytes
    mutable sal_uLong               mnBytesUsed;
    mutable long                mnLruIndex;
    mutable int                 mnGlyphCount;
    ServerFont*                 mpCurrentGCFont;

    class FreetypeManager*      mpFtManager;
};

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

class GlyphMetric
{
public:
    Point                   GetOffset() const   { return maOffset; }
    Point                   GetDelta() const    { return maDelta; }
    Size                    GetSize() const     { return maSize; }
    long                    GetCharWidth() const { return mnAdvanceWidth; }

protected:
    friend class GlyphData;
    void                    SetOffset( int nX, int nY ) { maOffset = Point( nX, nY); }
    void                    SetDelta( int nX, int nY )  { maDelta = Point( nX, nY); }
    void                    SetSize( const Size& s )    { maSize = s; }
    void                    SetCharWidth( long nW )     { mnAdvanceWidth = nW; }

private:
    long                    mnAdvanceWidth;
    Point                   maDelta;
    Point                   maOffset;
    Size                    maSize;
};

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

// the glyph specific data needed by a GlyphCachePeer is usually trivial,
// not attaching it to the corresponding GlyphData would be overkill;
// this is currently only used by the headless (aka svp) plugin, where meInfo is
// basebmp::Format and mpData is SvpGcpHelper*
struct ExtGlyphData
{
    int     meInfo;
    void*   mpData;

    ExtGlyphData() : meInfo(0), mpData(NULL) {}
};

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

class GlyphData
{
public:
    mnLruValue()
        : mnLruValue(0)
    {
    }

    const GlyphMetric&      GetMetric() const           { return maMetric; }
    Size                    GetSize() const             { return maMetric.GetSize(); }

    void                    SetSize( const Size& s)     { maMetric.SetSize( s ); }
    void                    SetOffset( int nX, int nY ) { maMetric.SetOffset( nX, nY ); }
    void                    SetDelta( int nX, int nY )  { maMetric.SetDelta( nX, nY ); }
    void                    SetCharWidth( long nW )     { maMetric.SetCharWidth( nW ); }

    void                    SetLruValue( int n ) const  { mnLruValue = n; }
    long                    GetLruValue() const         { return mnLruValue;}

    ExtGlyphData&           ExtDataRef()                { return maExtData; }
    const ExtGlyphData&     ExtDataRef() const          { return maExtData; }

private:
    GlyphMetric             maMetric;
    ExtGlyphData            maExtData;

    // used by GlyphCache for cache LRU algorithm
    mutable long            mnLruValue;
};

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

class FtFontInfo;

class VCL_DLLPUBLIC ServerFont
{
public:
    ServerFont( const FontSelectPattern&, FtFontInfo* );
    virtual ~ServerFont();

    const OString* GetFontFileName() const;
    bool                TestFont() const;
    FT_Face             GetFtFace() const;
    int                 GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); }
    void                SetFontOptions( boost::shared_ptr<ImplFontOptions> );
    boost::shared_ptr<ImplFontOptions> GetFontOptions() const;
    bool                NeedsArtificialBold() const { return mbArtBold; }
    bool                NeedsArtificialItalic() const { return mbArtItalic; }

    const FontSelectPattern&   GetFontSelData() const      { return maFontSelData; }

    void                FetchFontMetric( ImplFontMetricData&, long& rFactor ) const;
    const unsigned char* GetTable( const char* pName, sal_uLong* pLength );
    int                 GetEmUnits() const;
    const FT_Size_Metrics& GetMetricsFT() const { return maSizeFT->metrics; }
    const ImplFontCharMap* GetImplFontCharMap() const;
    bool                GetFontCapabilities(vcl::FontCapabilities &) const;

    GlyphData&                  GetGlyphData( sal_GlyphId );
    const GlyphMetric&          GetGlyphMetric( sal_GlyphId aGlyphId )
                                { return GetGlyphData( aGlyphId ).GetMetric(); }
#if ENABLE_GRAPHITE
    virtual GraphiteFaceWrapper* GetGraphiteFace() const;
#endif

    sal_GlyphId         GetGlyphIndex( sal_UCS4 ) const;
    sal_GlyphId         GetRawGlyphIndex( sal_UCS4, sal_UCS4 = 0 ) const;
    sal_GlyphId         FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const;
    bool                GetGlyphOutline( sal_GlyphId aGlyphId, ::basegfx::B2DPolyPolygon& ) const;
    bool                GetAntialiasAdvice( void ) const;
    bool                GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& ) const;
    bool                GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& ) const;

private:
    friend class GlyphCache;
    friend class ServerFontLayout;
    friend class ImplServerFontEntry;
    friend class X11SalGraphics;

    void                        AddRef() const      { ++mnRefCount; }
    long                        GetRefCount() const { return mnRefCount; }
    long                        Release() const;
    sal_uLong                       GetByteCount() const { return mnBytesUsed; }

    void                InitGlyphData( sal_GlyphId, GlyphData& ) const;
    void                GarbageCollect( long );
    void                        ReleaseFromGarbageCollect();

    int                 ApplyGlyphTransform( int nGlyphFlags, FT_GlyphRec_*, bool ) const;
    bool                ApplyGSUB( const FontSelectPattern& );

    ServerFontLayoutEngine* GetLayoutEngine();

    typedef ::boost::unordered_map<int,GlyphData> GlyphList;
    mutable GlyphList           maGlyphList;

    const FontSelectPattern    maFontSelData;

    // used by GlyphCache for cache LRU algorithm
    mutable long                mnRefCount;
    mutable sal_uLong               mnBytesUsed;

    ServerFont*                 mpPrevGCFont;
    ServerFont*                 mpNextGCFont;

    // 16.16 fixed point values used for a rotated font
    long                        mnCos;
    long                        mnSin;

    bool                        mbCollectedZW;

    int                         mnWidth;
    int                         mnPrioEmbedded;
    int                         mnPrioAntiAlias;
    int                         mnPrioAutoHint;
    FtFontInfo*                 mpFontInfo;
    FT_Int                      mnLoadFlags;
    double                      mfStretch;
    FT_FaceRec_*                maFaceFT;
    FT_SizeRec_*                maSizeFT;

    boost::shared_ptr<ImplFontOptions> mpFontOptions;

    bool                        mbFaceOk;
    bool            mbArtItalic;
    bool            mbArtBold;
    bool            mbUseGamma;

    typedef ::boost::unordered_map<int,int> GlyphSubstitution;
    GlyphSubstitution           maGlyphSubstitution;

    ServerFontLayoutEngine*     mpLayoutEngine;
};

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

// a class for cache entries for physical font instances that are based on serverfonts
class VCL_DLLPUBLIC ImplServerFontEntry : public ImplFontEntry
{
private:
    ServerFont*    mpServerFont;
    boost::shared_ptr<ImplFontOptions> mpFontOptions;
    bool           mbGotFontOptions;

public:
                   ImplServerFontEntry( FontSelectPattern& );
    virtual        ~ImplServerFontEntry();
    void           SetServerFont(ServerFont* p);
    void           HandleFontOptions();
};

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

class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout
{
private:
    ServerFont&     mrServerFont;
    com::sun::star::uno::Reference<com::sun::star::i18n::XBreakIterator> mxBreak;

    // enforce proper copy semantic
    SAL_DLLPRIVATE  ServerFontLayout( const ServerFontLayout& );
    SAL_DLLPRIVATE  ServerFontLayout& operator=( const ServerFontLayout& );

public:
                    ServerFontLayout( ServerFont& );
    virtual bool    LayoutText( ImplLayoutArgs& );
    virtual void    AdjustLayout( ImplLayoutArgs& );
    virtual void    DrawText( SalGraphics& ) const;
    void            setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nIndex,
                        bool bRightToLeft);

    ServerFont&     GetServerFont() const   { return mrServerFont; }
};

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

class ServerFontLayoutEngine
{
public:
    virtual         ~ServerFontLayoutEngine() {}
    virtual bool    layout(ServerFontLayout&, ImplLayoutArgs&) = 0;
};

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

class GlyphCachePeer
{
protected:
                    GlyphCachePeer() : mnBytesUsed(0) {}
    virtual         ~GlyphCachePeer() {}

public:
    sal_Int32       GetByteCount() const { return mnBytesUsed; }
    virtual void    RemovingFont( ServerFont& ) {}
    virtual void    RemovingGlyph( GlyphData& ) {}

protected:
    sal_Int32       mnBytesUsed;
};

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

class VCL_DLLPUBLIC RawBitmap
{
public:
                    RawBitmap();
                    ~RawBitmap();
    bool            Rotate( int nAngle );

public:
    basebmp::RawMemorySharedArray mpBits;
    sal_uLong           mnAllocated;

    sal_uLong           mnWidth;
    sal_uLong           mnHeight;

    sal_uLong           mnScanlineSize;
    sal_uLong           mnBitCount;

    int             mnXOffset;
    int             mnYOffset;
};

#endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#738922 Uninitialized scalar field<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX
#define INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX

#include <vcl/dllapi.h>

class GlyphCache;
class GlyphMetric;
class GlyphData;
class ServerFont;
class GlyphCachePeer;
class ServerFontLayoutEngine;
class ServerFontLayout;
class ImplFontOptions;

#include <tools/gen.hxx>
#include <basebmp/bitmapdevice.hxx>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>

namespace basegfx { class B2DPolyPolygon; }

class RawBitmap;

#include <outfont.hxx>
#include <impfont.hxx>

class ServerFontLayout;
#include <sallayout.hxx>

#include <config_graphite.h>
#if ENABLE_GRAPHITE
class GraphiteFaceWrapper;
#endif

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

namespace vcl
{
    struct FontCapabilities;
}

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

class VCL_DLLPUBLIC GlyphCache
{
public:
    explicit                    GlyphCache( GlyphCachePeer& );
    /*virtual*/                 ~GlyphCache();

    static GlyphCache&      GetInstance();

    void                        AddFontFile( const OString& rNormalizedName,
                                    int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes&);
    void                        AnnounceFonts( ImplDevFontList* ) const;

    ServerFont*                 CacheFont( const FontSelectPattern& );
    void                        UncacheFont( ServerFont& );
    void                        ClearFontCache();
    void                        InvalidateAllGlyphs();

protected:
    GlyphCachePeer&             mrPeer;

private:
    friend class ServerFont;
    // used by ServerFont class only
    void                        AddedGlyph( ServerFont&, GlyphData& );
    void                        RemovingGlyph( GlyphData& );
    void                        UsingGlyph( ServerFont&, GlyphData& );
    void                        GrowNotify();

private:
    void                        GarbageCollect();

    // the GlyphCache's FontList matches a font request to a serverfont instance
    // the FontList key's mpFontData member is reinterpreted as integer font id
    struct IFSD_Equal{  bool operator()( const FontSelectPattern&, const FontSelectPattern& ) const; };
    struct IFSD_Hash{ size_t operator()( const FontSelectPattern& ) const; };
    typedef ::boost::unordered_map<FontSelectPattern,ServerFont*,IFSD_Hash,IFSD_Equal > FontList;
    FontList                    maFontList;
    sal_uLong                       mnMaxSize;      // max overall cache size in bytes
    mutable sal_uLong               mnBytesUsed;
    mutable long                mnLruIndex;
    mutable int                 mnGlyphCount;
    ServerFont*                 mpCurrentGCFont;

    class FreetypeManager*      mpFtManager;
};

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

class GlyphMetric
{
public:
    GlyphMetric() : mnAdvanceWidth(0) {}

    Point                   GetOffset() const   { return maOffset; }
    Point                   GetDelta() const    { return maDelta; }
    Size                    GetSize() const     { return maSize; }
    long                    GetCharWidth() const { return mnAdvanceWidth; }

protected:
    friend class GlyphData;
    void                    SetOffset( int nX, int nY ) { maOffset = Point( nX, nY); }
    void                    SetDelta( int nX, int nY )  { maDelta = Point( nX, nY); }
    void                    SetSize( const Size& s )    { maSize = s; }
    void                    SetCharWidth( long nW )     { mnAdvanceWidth = nW; }

private:
    long                    mnAdvanceWidth;
    Point                   maDelta;
    Point                   maOffset;
    Size                    maSize;
};

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

// the glyph specific data needed by a GlyphCachePeer is usually trivial,
// not attaching it to the corresponding GlyphData would be overkill;
// this is currently only used by the headless (aka svp) plugin, where meInfo is
// basebmp::Format and mpData is SvpGcpHelper*
struct ExtGlyphData
{
    int     meInfo;
    void*   mpData;

    ExtGlyphData() : meInfo(0), mpData(NULL) {}
};

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

class GlyphData
{
public:
    GlyphData() : mnLruValue(0) {}

    const GlyphMetric&      GetMetric() const           { return maMetric; }
    Size                    GetSize() const             { return maMetric.GetSize(); }

    void                    SetSize( const Size& s)     { maMetric.SetSize( s ); }
    void                    SetOffset( int nX, int nY ) { maMetric.SetOffset( nX, nY ); }
    void                    SetDelta( int nX, int nY )  { maMetric.SetDelta( nX, nY ); }
    void                    SetCharWidth( long nW )     { maMetric.SetCharWidth( nW ); }

    void                    SetLruValue( int n ) const  { mnLruValue = n; }
    long                    GetLruValue() const         { return mnLruValue;}

    ExtGlyphData&           ExtDataRef()                { return maExtData; }
    const ExtGlyphData&     ExtDataRef() const          { return maExtData; }

private:
    GlyphMetric             maMetric;
    ExtGlyphData            maExtData;

    // used by GlyphCache for cache LRU algorithm
    mutable long            mnLruValue;
};

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

class FtFontInfo;

class VCL_DLLPUBLIC ServerFont
{
public:
    ServerFont( const FontSelectPattern&, FtFontInfo* );
    virtual ~ServerFont();

    const OString* GetFontFileName() const;
    bool                TestFont() const;
    FT_Face             GetFtFace() const;
    int                 GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); }
    void                SetFontOptions( boost::shared_ptr<ImplFontOptions> );
    boost::shared_ptr<ImplFontOptions> GetFontOptions() const;
    bool                NeedsArtificialBold() const { return mbArtBold; }
    bool                NeedsArtificialItalic() const { return mbArtItalic; }

    const FontSelectPattern&   GetFontSelData() const      { return maFontSelData; }

    void                FetchFontMetric( ImplFontMetricData&, long& rFactor ) const;
    const unsigned char* GetTable( const char* pName, sal_uLong* pLength );
    int                 GetEmUnits() const;
    const FT_Size_Metrics& GetMetricsFT() const { return maSizeFT->metrics; }
    const ImplFontCharMap* GetImplFontCharMap() const;
    bool                GetFontCapabilities(vcl::FontCapabilities &) const;

    GlyphData&                  GetGlyphData( sal_GlyphId );
    const GlyphMetric&          GetGlyphMetric( sal_GlyphId aGlyphId )
                                { return GetGlyphData( aGlyphId ).GetMetric(); }
#if ENABLE_GRAPHITE
    virtual GraphiteFaceWrapper* GetGraphiteFace() const;
#endif

    sal_GlyphId         GetGlyphIndex( sal_UCS4 ) const;
    sal_GlyphId         GetRawGlyphIndex( sal_UCS4, sal_UCS4 = 0 ) const;
    sal_GlyphId         FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const;
    bool                GetGlyphOutline( sal_GlyphId aGlyphId, ::basegfx::B2DPolyPolygon& ) const;
    bool                GetAntialiasAdvice( void ) const;
    bool                GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& ) const;
    bool                GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& ) const;

private:
    friend class GlyphCache;
    friend class ServerFontLayout;
    friend class ImplServerFontEntry;
    friend class X11SalGraphics;

    void                        AddRef() const      { ++mnRefCount; }
    long                        GetRefCount() const { return mnRefCount; }
    long                        Release() const;
    sal_uLong                       GetByteCount() const { return mnBytesUsed; }

    void                InitGlyphData( sal_GlyphId, GlyphData& ) const;
    void                GarbageCollect( long );
    void                        ReleaseFromGarbageCollect();

    int                 ApplyGlyphTransform( int nGlyphFlags, FT_GlyphRec_*, bool ) const;
    bool                ApplyGSUB( const FontSelectPattern& );

    ServerFontLayoutEngine* GetLayoutEngine();

    typedef ::boost::unordered_map<int,GlyphData> GlyphList;
    mutable GlyphList           maGlyphList;

    const FontSelectPattern    maFontSelData;

    // used by GlyphCache for cache LRU algorithm
    mutable long                mnRefCount;
    mutable sal_uLong               mnBytesUsed;

    ServerFont*                 mpPrevGCFont;
    ServerFont*                 mpNextGCFont;

    // 16.16 fixed point values used for a rotated font
    long                        mnCos;
    long                        mnSin;

    bool                        mbCollectedZW;

    int                         mnWidth;
    int                         mnPrioEmbedded;
    int                         mnPrioAntiAlias;
    int                         mnPrioAutoHint;
    FtFontInfo*                 mpFontInfo;
    FT_Int                      mnLoadFlags;
    double                      mfStretch;
    FT_FaceRec_*                maFaceFT;
    FT_SizeRec_*                maSizeFT;

    boost::shared_ptr<ImplFontOptions> mpFontOptions;

    bool                        mbFaceOk;
    bool            mbArtItalic;
    bool            mbArtBold;
    bool            mbUseGamma;

    typedef ::boost::unordered_map<int,int> GlyphSubstitution;
    GlyphSubstitution           maGlyphSubstitution;

    ServerFontLayoutEngine*     mpLayoutEngine;
};

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

// a class for cache entries for physical font instances that are based on serverfonts
class VCL_DLLPUBLIC ImplServerFontEntry : public ImplFontEntry
{
private:
    ServerFont*    mpServerFont;
    boost::shared_ptr<ImplFontOptions> mpFontOptions;
    bool           mbGotFontOptions;

public:
                   ImplServerFontEntry( FontSelectPattern& );
    virtual        ~ImplServerFontEntry();
    void           SetServerFont(ServerFont* p);
    void           HandleFontOptions();
};

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

class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout
{
private:
    ServerFont&     mrServerFont;
    com::sun::star::uno::Reference<com::sun::star::i18n::XBreakIterator> mxBreak;

    // enforce proper copy semantic
    SAL_DLLPRIVATE  ServerFontLayout( const ServerFontLayout& );
    SAL_DLLPRIVATE  ServerFontLayout& operator=( const ServerFontLayout& );

public:
                    ServerFontLayout( ServerFont& );
    virtual bool    LayoutText( ImplLayoutArgs& );
    virtual void    AdjustLayout( ImplLayoutArgs& );
    virtual void    DrawText( SalGraphics& ) const;
    void            setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nIndex,
                        bool bRightToLeft);

    ServerFont&     GetServerFont() const   { return mrServerFont; }
};

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

class ServerFontLayoutEngine
{
public:
    virtual         ~ServerFontLayoutEngine() {}
    virtual bool    layout(ServerFontLayout&, ImplLayoutArgs&) = 0;
};

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

class GlyphCachePeer
{
protected:
                    GlyphCachePeer() : mnBytesUsed(0) {}
    virtual         ~GlyphCachePeer() {}

public:
    sal_Int32       GetByteCount() const { return mnBytesUsed; }
    virtual void    RemovingFont( ServerFont& ) {}
    virtual void    RemovingGlyph( GlyphData& ) {}

protected:
    sal_Int32       mnBytesUsed;
};

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

class VCL_DLLPUBLIC RawBitmap
{
public:
                    RawBitmap();
                    ~RawBitmap();
    bool            Rotate( int nAngle );

public:
    basebmp::RawMemorySharedArray mpBits;
    sal_uLong           mnAllocated;

    sal_uLong           mnWidth;
    sal_uLong           mnHeight;

    sal_uLong           mnScanlineSize;
    sal_uLong           mnBitCount;

    int             mnXOffset;
    int             mnYOffset;
};

#endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before><commit_msg>vcl: remove newlines from stacking.cxx<commit_after><|endoftext|>