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

#include "chrome/browser/ui/gtk/global_menu_bar.h"

#include <gtk/gtk.h>

#include "base/command_line.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/gtk_util.h"

struct GlobalMenuBarCommand {
  int str_id;
  int command;
  int tag;
};

namespace {

const int MENU_SEPARATOR =-1;
const int MENU_END = -2;
const int MENU_DISABLED_LABEL = -3;

GlobalMenuBarCommand file_menu[] = {
  { IDS_NEW_TAB, IDC_NEW_TAB },
  { IDS_NEW_WINDOW, IDC_NEW_WINDOW },
  { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW },
  { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB },
  { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE },
  { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_CREATE_SHORTCUTS, IDC_CREATE_SHORTCUTS },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_CLOSE_WINDOW_LINUX, IDC_CLOSE_WINDOW },
  { IDS_CLOSE_TAB_LINUX, IDC_CLOSE_TAB },
  { IDS_SAVE_PAGE, IDC_SAVE_PAGE },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_PRINT, IDC_PRINT },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand edit_menu[] = {
  { IDS_CUT, IDC_CUT },
  { IDS_COPY, IDC_COPY },
  { IDS_PASTE, IDC_PASTE },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_FIND, IDC_FIND },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_PREFERENCES, IDC_OPTIONS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand view_menu[] = {
  { IDS_SHOW_BOOKMARK_BAR, IDC_SHOW_BOOKMARK_BAR },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_STOP_MENU_LINUX, IDC_STOP },
  { IDS_RELOAD_MENU_LINUX, IDC_RELOAD },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_FULLSCREEN, IDC_FULLSCREEN },
  { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL },
  { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS },
  { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand history_menu[] = {
  { IDS_HISTORY_HOME_LINUX, IDC_HOME },
  { IDS_HISTORY_BACK_LINUX, IDC_BACK },
  { IDS_HISTORY_FORWARD_LINUX, IDC_FORWARD },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_HISTORY_VISITED_LINUX, MENU_DISABLED_LABEL,
    GlobalMenuBar::TAG_MOST_VISITED_HEADER },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_HISTORY_CLOSED_LINUX, MENU_DISABLED_LABEL,
    GlobalMenuBar::TAG_RECENTLY_CLOSED_HEADER },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_SHOWFULLHISTORY_LINK, IDC_SHOW_HISTORY },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand bookmark_menu[] = {
  { IDS_BOOKMARK_MANAGER, IDC_SHOW_BOOKMARK_MANAGER },
  { IDS_BOOKMARK_CURRENT_PAGE_LINUX, IDC_BOOKMARK_PAGE },
  { IDS_BOOKMARK_ALL_TABS_LINUX, IDC_BOOKMARK_ALL_TABS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand tools_menu[] = {
  { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
  { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
  { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_TASK_MANAGER, IDC_TASK_MANAGER },
  { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
  { IDS_DEV_TOOLS, IDC_DEV_TOOLS },
  { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand help_menu[] = {
  { IDS_FEEDBACK, IDC_FEEDBACK },
  { IDS_HELP_PAGE , IDC_HELP_PAGE },
  { MENU_END, MENU_END }
};

}  // namespace

GlobalMenuBar::GlobalMenuBar(Browser* browser)
    : browser_(browser),
      profile_(browser_->profile()),
      menu_bar_(gtk_menu_bar_new()),
      history_menu_(browser_),
      dummy_accel_group_(gtk_accel_group_new()),
      block_activation_(false) {
  // The global menu bar should never actually be shown in the app; it should
  // instead remain in our widget hierarchy simply to be noticed by third party
  // components.
  gtk_widget_set_no_show_all(menu_bar_.get(), TRUE);

  // Set a nice name so it shows up in gtkparasite and others.
  gtk_widget_set_name(menu_bar_.get(), "chrome-hidden-global-menubar");

  BuildGtkMenuFrom(IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu, NULL);
  BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu, NULL);
  BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu, NULL);
  BuildGtkMenuFrom(IDS_HISTORY_MENU_LINUX, &id_to_menu_item_,
                   history_menu, &history_menu_);

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableGlobalBookmarkMenu)) {
    // TODO(erg): dbusmenu-glib in Ubuntu Natty does not like it when we shove
    // 100k or more of favicon data over it. Users have reported that the
    // browser hangs on startup for over a minute and breaking during this time
    // shows a stack entirely of dbus/glib code (See #86715).  For now, just
    // hide the menu until appmenu-gtk catches up and doesn't hang if we throw
    // (potentially) megs of icon data at it. (Some of our users have thousands
    // of bookmarks and we're already unacceptably laggy at 100.)
    //
    // http://crbug.com/86715, http://crbug.com/85466
    bookmark_menu_.reset(new GlobalBookmarkMenu(browser_));
    BuildGtkMenuFrom(IDS_BOOKMARKS_MENU_LINUX, &id_to_menu_item_, bookmark_menu,
                     bookmark_menu_.get());
  }

  BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX, &id_to_menu_item_, tools_menu, NULL);
  BuildGtkMenuFrom(IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu, NULL);

  for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
       it != id_to_menu_item_.end(); ++it) {
    // Get the starting enabled state.
    gtk_widget_set_sensitive(
        it->second,
        browser_->command_updater()->IsCommandEnabled(it->first));

    // Set the accelerator for each menu item.
    const ui::AcceleratorGtk* accelerator_gtk =
        AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
            it->first);
    if (accelerator_gtk) {
      gtk_widget_add_accelerator(it->second,
                                 "activate",
                                 dummy_accel_group_,
                                 accelerator_gtk->GetGdkKeyCode(),
                                 accelerator_gtk->gdk_modifier_type(),
                                 GTK_ACCEL_VISIBLE);
    }

    browser_->command_updater()->AddCommandObserver(it->first, this);
  }

  // Listen for bookmark bar visibility changes and set the initial state.
  registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
                 NotificationService::AllSources());
  Observe(NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
          NotificationService::AllSources(),
          NotificationService::NoDetails());
}

GlobalMenuBar::~GlobalMenuBar() {
  for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
       it != id_to_menu_item_.end(); ++it) {
    browser_->command_updater()->RemoveCommandObserver(it->first, this);
  }

  g_object_unref(dummy_accel_group_);
}

void GlobalMenuBar::BuildGtkMenuFrom(
    int menu_str_id,
    std::map<int, GtkWidget*>* id_to_menu_item,
    GlobalMenuBarCommand* commands,
    GlobalMenuOwner* owner) {
  GtkWidget* menu = gtk_menu_new();
  for (int i = 0; commands[i].str_id != MENU_END; ++i) {
    GtkWidget* menu_item = BuildMenuItem(
        commands[i].str_id, commands[i].command, commands[i].tag,
        id_to_menu_item, menu);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
  }

  gtk_widget_show(menu);

  GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
      gfx::ConvertAcceleratorsFromWindowsStyle(
          l10n_util::GetStringUTF8(menu_str_id)).c_str());

  // Give the owner a chance to sink the reference before we add it to the menu
  // bar.
  if (owner)
    owner->Init(menu, menu_item);

  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_.get()), menu_item);
}

GtkWidget* GlobalMenuBar::BuildMenuItem(
    int string_id,
    int command_id,
    int tag_id,
    std::map<int, GtkWidget*>* id_to_menu_item,
    GtkWidget* menu_to_add_to) {
  GtkWidget* menu_item = NULL;
  if (string_id == MENU_SEPARATOR) {
    menu_item = gtk_separator_menu_item_new();
  } else {
    std::string label =
        gfx::ConvertAcceleratorsFromWindowsStyle(
            l10n_util::GetStringUTF8(string_id));

    if (command_id == IDC_SHOW_BOOKMARK_BAR)
      menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
    else
      menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());

    if (tag_id) {
      g_object_set_data(G_OBJECT(menu_item), "type-tag",
                        GINT_TO_POINTER(tag_id));
    }

    if (command_id == MENU_DISABLED_LABEL) {
      gtk_widget_set_sensitive(menu_item, FALSE);
    } else {
      id_to_menu_item->insert(std::make_pair(command_id, menu_item));
      g_object_set_data(G_OBJECT(menu_item), "command-id",
                        GINT_TO_POINTER(command_id));
      g_signal_connect(menu_item, "activate",
                       G_CALLBACK(OnItemActivatedThunk), this);
    }
  }
  gtk_widget_show(menu_item);
  return menu_item;
}

void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) {
  CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
  if (it != id_to_menu_item_.end())
    gtk_widget_set_sensitive(it->second, enabled);
}

void GlobalMenuBar::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK(type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED);

  CommandIDMenuItemMap::iterator it =
      id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
  if (it != id_to_menu_item_.end()) {
    PrefService* prefs = browser_->profile()->GetPrefs();

    block_activation_ = true;
    gtk_check_menu_item_set_active(
        GTK_CHECK_MENU_ITEM(it->second),
        prefs->GetBoolean(prefs::kShowBookmarkBar));
    block_activation_ = false;
  }
}

void GlobalMenuBar::OnItemActivated(GtkWidget* sender) {
  if (block_activation_)
    return;

  int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender), "command-id"));
  browser_->ExecuteCommandIfEnabled(id);
}
<commit_msg>gtk: Fix alt-f/e to bring up the wrench menu.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/gtk/global_menu_bar.h"

#include <gtk/gtk.h>

#include "base/command_line.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/gtk_util.h"

struct GlobalMenuBarCommand {
  int str_id;
  int command;
  int tag;
};

namespace {

const int MENU_SEPARATOR =-1;
const int MENU_END = -2;
const int MENU_DISABLED_LABEL = -3;

GlobalMenuBarCommand file_menu[] = {
  { IDS_NEW_TAB, IDC_NEW_TAB },
  { IDS_NEW_WINDOW, IDC_NEW_WINDOW },
  { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW },
  { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB },
  { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE },
  { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_CREATE_SHORTCUTS, IDC_CREATE_SHORTCUTS },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_CLOSE_WINDOW_LINUX, IDC_CLOSE_WINDOW },
  { IDS_CLOSE_TAB_LINUX, IDC_CLOSE_TAB },
  { IDS_SAVE_PAGE, IDC_SAVE_PAGE },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_PRINT, IDC_PRINT },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand edit_menu[] = {
  { IDS_CUT, IDC_CUT },
  { IDS_COPY, IDC_COPY },
  { IDS_PASTE, IDC_PASTE },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_FIND, IDC_FIND },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_PREFERENCES, IDC_OPTIONS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand view_menu[] = {
  { IDS_SHOW_BOOKMARK_BAR, IDC_SHOW_BOOKMARK_BAR },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_STOP_MENU_LINUX, IDC_STOP },
  { IDS_RELOAD_MENU_LINUX, IDC_RELOAD },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_FULLSCREEN, IDC_FULLSCREEN },
  { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL },
  { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS },
  { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand history_menu[] = {
  { IDS_HISTORY_HOME_LINUX, IDC_HOME },
  { IDS_HISTORY_BACK_LINUX, IDC_BACK },
  { IDS_HISTORY_FORWARD_LINUX, IDC_FORWARD },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_HISTORY_VISITED_LINUX, MENU_DISABLED_LABEL,
    GlobalMenuBar::TAG_MOST_VISITED_HEADER },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_HISTORY_CLOSED_LINUX, MENU_DISABLED_LABEL,
    GlobalMenuBar::TAG_RECENTLY_CLOSED_HEADER },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_SHOWFULLHISTORY_LINK, IDC_SHOW_HISTORY },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand bookmark_menu[] = {
  { IDS_BOOKMARK_MANAGER, IDC_SHOW_BOOKMARK_MANAGER },
  { IDS_BOOKMARK_CURRENT_PAGE_LINUX, IDC_BOOKMARK_PAGE },
  { IDS_BOOKMARK_ALL_TABS_LINUX, IDC_BOOKMARK_ALL_TABS },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand tools_menu[] = {
  { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
  { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
  { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_TASK_MANAGER, IDC_TASK_MANAGER },
  { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA },

  { MENU_SEPARATOR, MENU_SEPARATOR },

  { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
  { IDS_DEV_TOOLS, IDC_DEV_TOOLS },
  { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },

  { MENU_END, MENU_END }
};

GlobalMenuBarCommand help_menu[] = {
  { IDS_FEEDBACK, IDC_FEEDBACK },
  { IDS_HELP_PAGE , IDC_HELP_PAGE },
  { MENU_END, MENU_END }
};

}  // namespace

GlobalMenuBar::GlobalMenuBar(Browser* browser)
    : browser_(browser),
      profile_(browser_->profile()),
      menu_bar_(gtk_menu_bar_new()),
      history_menu_(browser_),
      dummy_accel_group_(gtk_accel_group_new()),
      block_activation_(false) {
  // The global menu bar should never actually be shown in the app; it should
  // instead remain in our widget hierarchy simply to be noticed by third party
  // components.
  gtk_widget_set_no_show_all(menu_bar_.get(), TRUE);

  // Set a nice name so it shows up in gtkparasite and others.
  gtk_widget_set_name(menu_bar_.get(), "chrome-hidden-global-menubar");

  BuildGtkMenuFrom(IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu, NULL);
  BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu, NULL);
  BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu, NULL);
  BuildGtkMenuFrom(IDS_HISTORY_MENU_LINUX, &id_to_menu_item_,
                   history_menu, &history_menu_);

  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableGlobalBookmarkMenu)) {
    // TODO(erg): dbusmenu-glib in Ubuntu Natty does not like it when we shove
    // 100k or more of favicon data over it. Users have reported that the
    // browser hangs on startup for over a minute and breaking during this time
    // shows a stack entirely of dbus/glib code (See #86715).  For now, just
    // hide the menu until appmenu-gtk catches up and doesn't hang if we throw
    // (potentially) megs of icon data at it. (Some of our users have thousands
    // of bookmarks and we're already unacceptably laggy at 100.)
    //
    // http://crbug.com/86715, http://crbug.com/85466
    bookmark_menu_.reset(new GlobalBookmarkMenu(browser_));
    BuildGtkMenuFrom(IDS_BOOKMARKS_MENU_LINUX, &id_to_menu_item_, bookmark_menu,
                     bookmark_menu_.get());
  }

  BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX, &id_to_menu_item_, tools_menu, NULL);
  BuildGtkMenuFrom(IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu, NULL);

  for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
       it != id_to_menu_item_.end(); ++it) {
    // Get the starting enabled state.
    gtk_widget_set_sensitive(
        it->second,
        browser_->command_updater()->IsCommandEnabled(it->first));

    // Set the accelerator for each menu item.
    const ui::AcceleratorGtk* accelerator_gtk =
        AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
            it->first);
    if (accelerator_gtk) {
      gtk_widget_add_accelerator(it->second,
                                 "activate",
                                 dummy_accel_group_,
                                 accelerator_gtk->GetGdkKeyCode(),
                                 accelerator_gtk->gdk_modifier_type(),
                                 GTK_ACCEL_VISIBLE);
    }

    browser_->command_updater()->AddCommandObserver(it->first, this);
  }

  // Listen for bookmark bar visibility changes and set the initial state.
  registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
                 NotificationService::AllSources());
  Observe(NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
          NotificationService::AllSources(),
          NotificationService::NoDetails());
}

GlobalMenuBar::~GlobalMenuBar() {
  for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
       it != id_to_menu_item_.end(); ++it) {
    browser_->command_updater()->RemoveCommandObserver(it->first, this);
  }

  g_object_unref(dummy_accel_group_);
}

void GlobalMenuBar::BuildGtkMenuFrom(
    int menu_str_id,
    std::map<int, GtkWidget*>* id_to_menu_item,
    GlobalMenuBarCommand* commands,
    GlobalMenuOwner* owner) {
  GtkWidget* menu = gtk_menu_new();
  for (int i = 0; commands[i].str_id != MENU_END; ++i) {
    GtkWidget* menu_item = BuildMenuItem(
        commands[i].str_id, commands[i].command, commands[i].tag,
        id_to_menu_item, menu);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
  }

  gtk_widget_show(menu);

  GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
      gfx::RemoveWindowsStyleAccelerators(
          l10n_util::GetStringUTF8(menu_str_id)).c_str());

  // Give the owner a chance to sink the reference before we add it to the menu
  // bar.
  if (owner)
    owner->Init(menu, menu_item);

  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_.get()), menu_item);
}

GtkWidget* GlobalMenuBar::BuildMenuItem(
    int string_id,
    int command_id,
    int tag_id,
    std::map<int, GtkWidget*>* id_to_menu_item,
    GtkWidget* menu_to_add_to) {
  GtkWidget* menu_item = NULL;
  if (string_id == MENU_SEPARATOR) {
    menu_item = gtk_separator_menu_item_new();
  } else {
    std::string label =
        gfx::ConvertAcceleratorsFromWindowsStyle(
            l10n_util::GetStringUTF8(string_id));

    if (command_id == IDC_SHOW_BOOKMARK_BAR)
      menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
    else
      menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());

    if (tag_id) {
      g_object_set_data(G_OBJECT(menu_item), "type-tag",
                        GINT_TO_POINTER(tag_id));
    }

    if (command_id == MENU_DISABLED_LABEL) {
      gtk_widget_set_sensitive(menu_item, FALSE);
    } else {
      id_to_menu_item->insert(std::make_pair(command_id, menu_item));
      g_object_set_data(G_OBJECT(menu_item), "command-id",
                        GINT_TO_POINTER(command_id));
      g_signal_connect(menu_item, "activate",
                       G_CALLBACK(OnItemActivatedThunk), this);
    }
  }
  gtk_widget_show(menu_item);
  return menu_item;
}

void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) {
  CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
  if (it != id_to_menu_item_.end())
    gtk_widget_set_sensitive(it->second, enabled);
}

void GlobalMenuBar::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK(type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED);

  CommandIDMenuItemMap::iterator it =
      id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
  if (it != id_to_menu_item_.end()) {
    PrefService* prefs = browser_->profile()->GetPrefs();

    block_activation_ = true;
    gtk_check_menu_item_set_active(
        GTK_CHECK_MENU_ITEM(it->second),
        prefs->GetBoolean(prefs::kShowBookmarkBar));
    block_activation_ = false;
  }
}

void GlobalMenuBar::OnItemActivated(GtkWidget* sender) {
  if (block_activation_)
    return;

  int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender), "command-id"));
  browser_->ExecuteCommandIfEnabled(id);
}
<|endoftext|>


<commit_before>#include "StdAfx.h"

#include "illa/types.h"

using Geom::RectInt;
using Geom::SizeInt;
using Geom::PointInt;

/*******
	RECT
	*******/

SUITE(RectangleSuite)
{

	TEST(Default_Ctor)
	{
		Geom::RectInt r;
		CHECK(r.Width() == 0);
		CHECK(r.Height() == 0);
	}

	TEST(Ctor_Point_Size)
	{
		Geom::RectInt r(Geom::PointInt(300, 400), Geom::SizeInt(100, 200));
		CHECK(r.Width() == 100);
		CHECK(r.Height() == 200);
		CHECK(r.Left() == 300);
		CHECK(r.Top() == 400);
	}

	TEST(Ctor_Point_Point)
	{
		Geom::RectInt r(Geom::PointInt(300, 400), Geom::PointInt(100, 200));
		CHECK(r.Width() == 200);
		CHECK(r.Height() == 200);
		CHECK(r.Left() == 100);
		CHECK(r.Top() == 200);
	}

	TEST(Consistency)
	{
		Geom::RectInt r(PointInt(500, 100), SizeInt(100, 200));
		CHECK(r.Width() == r.Right() - r.Left());
		CHECK(r.Height() == r.Bottom() - r.Top());
	}

	TEST(Crop) {
		RectInt r1(PointInt(100, 200), PointInt(300, 400));
		RectInt r2(PointInt(0, 10), PointInt(333, 323));
		CHECK_EQUAL(RectInt(PointInt(100, 200), PointInt(300, 323)), r1.Crop(r2));
		CHECK_EQUAL(r1.Crop(r2), r2.Crop(r1));
	}

	TEST(ClipSize) {
		RectInt dstCanvas{ { 0, 0 }, PointInt{ 400, 400 } };
		RectInt srcCanvas{ { 0, 0 }, PointInt{ 200, 200 } };

		CHECK_EQUAL(RectInt({ 50, 50 }, PointInt{ 100, 100 }),
			Geomz::ClipSource(dstCanvas, PointInt{ 100, 200 }, srcCanvas, PointInt{ 50, 50 }, SizeInt{ 50, 50 }));

		CHECK_EQUAL(RectInt({ 50, 50 }, PointInt{ 200, 200 }),
			Geomz::ClipSource(dstCanvas, PointInt{ 100, 200 }, srcCanvas, PointInt{ 50, 50 }, SizeInt{ 999, 999 }));
	}
}

/*******
	PointInt
	*******/
SUITE(Point)
{
	TEST(Default_Ctor)
	{
		PointInt p;
		CHECK(p.X == 0);
		CHECK(p.Y == 0);
	}

	TEST(Flipping) {
		PointInt p(9, 4);
		PointInt q = p.Flipped();
		CHECK_EQUAL(9, p.X);
		CHECK_EQUAL(4, p.Y);
		CHECK_EQUAL(4, q.X);
		CHECK_EQUAL(9, q.Y);
	}

	TEST(Comp)
	{
		PointInt p1(5, 7), p2(5, 9), p3(6, 7), p4(7, 5), p5(5, 7);
		CHECK(p1 != p2);
		CHECK(p1 != p3);
		CHECK(p1 != p4);
		CHECK(p1 == p5);
	}

	TEST(Add)
	{
		PointInt p1(5, 7), p2(15, 23);
		PointInt p3 = p1 + p2;
		CHECK(p3 == PointInt(20, 30));

		p1 += p2;
		CHECK(p1 == p3);
	}

	TEST(Sub)
	{
		PointInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 - p2;
		CHECK(p3 == SizeInt(-10, -16));

		p1 -= SizeInt(p1.X, p1.Y);
		CHECK(p1 == PointInt(0, 0));
	}
}

/*******
	SizeInt
	*******/
SUITE(Size)
{
	TEST(Default_Ctor)
	{
		SizeInt s;
		CHECK(s.Width == 0);
		CHECK(s.Height == 0);
	}

	TEST(Flipping) {
		SizeInt p(9, 4);
		SizeInt q = p.Flipped();
		CHECK_EQUAL(9, p.Width);
		CHECK_EQUAL(4, p.Height);
		CHECK_EQUAL(4, q.Width);
		CHECK_EQUAL(9, q.Height);
	}

	TEST(Comp)
	{
		SizeInt p1(5, 7), p2(5, 9), p3(6, 7), p4(7, 5), p5(5, 7);
		CHECK(p1 != p2);
		CHECK(p1 != p3);
		CHECK(p1 != p4);
		CHECK(p1 == p5);
	}

	TEST(Add)
	{
		SizeInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 + p2;
		CHECK(p3 == SizeInt(20, 30));
	}

	TEST(Sub)
	{
		SizeInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 - p2;
		CHECK(p3 == SizeInt(-10, -16));
	}

	using Util::Min;

	TEST(TripleMin) {
		CHECK_EQUAL(SizeInt(-5, -6), Minimum(SizeInt(30, -6), SizeInt(-2, 40), SizeInt(-5, 20)));
	}
}
<commit_msg>Fix tests for Geom::ClipSource<commit_after>#include "StdAfx.h"

#include "illa/types.h"

using Geom::RectInt;
using Geom::SizeInt;
using Geom::PointInt;

/*******
	RECT
	*******/

SUITE(RectangleSuite)
{

	TEST(Default_Ctor)
	{
		Geom::RectInt r;
		CHECK(r.Width() == 0);
		CHECK(r.Height() == 0);
	}

	TEST(Ctor_Point_Size)
	{
		Geom::RectInt r(Geom::PointInt(300, 400), Geom::SizeInt(100, 200));
		CHECK(r.Width() == 100);
		CHECK(r.Height() == 200);
		CHECK(r.Left() == 300);
		CHECK(r.Top() == 400);
	}

	TEST(Ctor_Point_Point)
	{
		Geom::RectInt r(Geom::PointInt(300, 400), Geom::PointInt(100, 200));
		CHECK(r.Width() == 200);
		CHECK(r.Height() == 200);
		CHECK(r.Left() == 100);
		CHECK(r.Top() == 200);
	}

	TEST(Consistency)
	{
		Geom::RectInt r(PointInt(500, 100), SizeInt(100, 200));
		CHECK(r.Width() == r.Right() - r.Left());
		CHECK(r.Height() == r.Bottom() - r.Top());
	}

	TEST(Crop) {
		RectInt r1(PointInt(100, 200), PointInt(300, 400));
		RectInt r2(PointInt(0, 10), PointInt(333, 323));
		CHECK_EQUAL(RectInt(PointInt(100, 200), PointInt(300, 323)), r1.Crop(r2));
		CHECK_EQUAL(r1.Crop(r2), r2.Crop(r1));
	}

	TEST(ClipSize) {
		RectInt dstCanvas{ { 0, 0 }, PointInt{ 400, 400 } };
		RectInt srcCanvas{ { 0, 0 }, PointInt{ 200, 200 } };

		auto a = Geom::ClipSource(dstCanvas, PointInt{ 100, 200 }, srcCanvas, PointInt{ 50, 50 }, SizeInt{ 50, 50 });
		CHECK_EQUAL(RectInt({ 50, 50 }, PointInt{ 100, 100 }), a);

		auto b = Geom::ClipSource(dstCanvas, PointInt{ 100, 200 }, srcCanvas, PointInt{ 50, 50 }, SizeInt{ 999, 999 });
		CHECK_EQUAL(RectInt({ 50, 50 }, PointInt{ 200, 200 }), b);
	}
}

/*******
	PointInt
	*******/
SUITE(Point)
{
	TEST(Default_Ctor)
	{
		PointInt p;
		CHECK(p.X == 0);
		CHECK(p.Y == 0);
	}

	TEST(Flipping) {
		PointInt p(9, 4);
		PointInt q = p.Flipped();
		CHECK_EQUAL(9, p.X);
		CHECK_EQUAL(4, p.Y);
		CHECK_EQUAL(4, q.X);
		CHECK_EQUAL(9, q.Y);
	}

	TEST(Comp)
	{
		PointInt p1(5, 7), p2(5, 9), p3(6, 7), p4(7, 5), p5(5, 7);
		CHECK(p1 != p2);
		CHECK(p1 != p3);
		CHECK(p1 != p4);
		CHECK(p1 == p5);
	}

	TEST(Add)
	{
		PointInt p1(5, 7), p2(15, 23);
		PointInt p3 = p1 + p2;
		CHECK(p3 == PointInt(20, 30));

		p1 += p2;
		CHECK(p1 == p3);
	}

	TEST(Sub)
	{
		PointInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 - p2;
		CHECK(p3 == SizeInt(-10, -16));

		p1 -= SizeInt(p1.X, p1.Y);
		CHECK(p1 == PointInt(0, 0));
	}
}

/*******
	SizeInt
	*******/
SUITE(Size)
{
	TEST(Default_Ctor)
	{
		SizeInt s;
		CHECK(s.Width == 0);
		CHECK(s.Height == 0);
	}

	TEST(Flipping) {
		SizeInt p(9, 4);
		SizeInt q = p.Flipped();
		CHECK_EQUAL(9, p.Width);
		CHECK_EQUAL(4, p.Height);
		CHECK_EQUAL(4, q.Width);
		CHECK_EQUAL(9, q.Height);
	}

	TEST(Comp)
	{
		SizeInt p1(5, 7), p2(5, 9), p3(6, 7), p4(7, 5), p5(5, 7);
		CHECK(p1 != p2);
		CHECK(p1 != p3);
		CHECK(p1 != p4);
		CHECK(p1 == p5);
	}

	TEST(Add)
	{
		SizeInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 + p2;
		CHECK(p3 == SizeInt(20, 30));
	}

	TEST(Sub)
	{
		SizeInt p1(5, 7), p2(15, 23);
		SizeInt p3 = p1 - p2;
		CHECK(p3 == SizeInt(-10, -16));
	}

	using Util::Min;

	TEST(TripleMin) {
		CHECK_EQUAL(SizeInt(-5, -6), Minimum(SizeInt(30, -6), SizeInt(-2, 40), SizeInt(-5, 20)));
	}
}
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------
//
// Copyright (C) 2016 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include <boost/python.hpp>
#include <deal.II/base/point.h>

namespace PyDealII
{

  template <int dim>
  double get_x(const dealii::Point<dim> &point)
  {
    return point(0);
  }

  template <int dim>
  double get_y(const dealii::Point<dim> &point)
  {
    return point(1);
  }

  void export_point()
  {
    boost::python::class_<dealii::Point<2>> ("Point", "Constructor. Requires x and y.",
                                             boost::python::init<double, double>())
                                         .add_property("x", get_x<2>, "Return the x component of the point.")
                                         .add_property("y", get_y<2>, "Return the y component of the point.");
  }

}
<commit_msg>Improve Point interface.<commit_after>// ---------------------------------------------------------------------
//
// Copyright (C) 2016 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include <boost/python.hpp>
#include <deal.II/base/point.h>
#include <deal.II/base/exceptions.h>

namespace PyDealII
{
  class PointWrapper
  {
  public:
    PointWrapper(boost::python::list list);
    double get_x();
    void set_x(double x);
    double get_y();
    void set_y(double y);
    double get_z();
    void set_z(double z);

  private:
    int dim;
    std::shared_ptr<void> point;
  };

  PointWrapper::PointWrapper(boost::python::list coord)
  {
    dim = boost::python::len(coord);
    if (dim == 2)
      point.reset(new dealii::Point<2> (boost::python::extract<double>(coord[0]),
                                        boost::python::extract<double>(coord[1])));
    else if (dim == 3)
      point.reset(new dealii::Point<3> (boost::python::extract<double>(coord[0]),
                                        boost::python::extract<double>(coord[1]),
                                        boost::python::extract<double>(coord[2])));
    else
      AssertThrow(false,
                  dealii::ExcMessage("The list of coordinates must contain two or three elements."));
  }

  double PointWrapper::get_x()
  {
    if (dim == 2)
      return (*std::static_pointer_cast<dealii::Point<2>>(point))(0);
    else
      return (*std::static_pointer_cast<dealii::Point<3>>(point))(0);
  }

  void PointWrapper::set_x(double x)
  {
    if (dim == 2)
      (*std::static_pointer_cast<dealii::Point<2>>(point))(0) = x;
    else
      (*std::static_pointer_cast<dealii::Point<3>>(point))(0) = x;
  }

  double PointWrapper::get_y()
  {
    if (dim == 2)
      return (*std::static_pointer_cast<dealii::Point<2>>(point))(1);
    else
      return (*std::static_pointer_cast<dealii::Point<3>>(point))(1);
  }

  void PointWrapper::set_y(double y)
  {
    if (dim == 2)
      (*std::static_pointer_cast<dealii::Point<2>>(point))(1) = y;
    else
      (*std::static_pointer_cast<dealii::Point<3>>(point))(1) = y;
  }

  double PointWrapper::get_z()
  {
    if (dim == 3)
      return (*std::static_pointer_cast<dealii::Point<3>>(point))(2);
    else
      AssertThrow(false,
                  dealii::ExcMessage("The z coordinate is only available for three-dimensional points"));
  }

  void PointWrapper::set_z(double z)
  {
    if (dim == 3)
      (*std::static_pointer_cast<dealii::Point<3>>(point))(2) = z;
    else
      AssertThrow(false,
                  dealii::ExcMessage("The z coordinate is only available for three-dimensional points"));
  }

  void export_point()
  {
    boost::python::class_<PointWrapper> ("Point",boost::python::init<boost::python::list>())
    .add_property("x", &PointWrapper::get_x, &PointWrapper::set_x, "Get the x component of the point.")
    .add_property("y", &PointWrapper::get_y, &PointWrapper::set_y, "Get the y component of the point.")
    .add_property("z", &PointWrapper::get_z, &PointWrapper::set_z, "Get the z component of the point.");
  }

}
<|endoftext|>


<commit_before>#include <cassert>
#include "triton/ir/constant.h"
#include "triton/ir/type.h"
#include "triton/ir/context.h"
#include "triton/ir/context_impl.h"

namespace triton{
namespace ir{

// constant

constant *constant::get_null_value(type *ty) {
  context &ctx = ty->get_context();
  switch (ty->get_scalar_ty()->get_type_id()) {
  case type::IntegerTyID:
    return constant_int::get(ty, 0);
  case type::HalfTyID:
    return constant_fp::get(type::get_half_ty(ctx), 0);
  case type::FloatTyID:
    return constant_fp::get(type::get_float_ty(ctx), 0);
  case type::DoubleTyID:
    return constant_fp::get(type::get_double_ty(ctx), 0);
  default:
    throw std::runtime_error("Cannot create a null constant of that type!");
  }
}

// FIXME

constant *constant::get_all_ones_value(type *ty) {
  if(ty->is_integer_ty())
    return constant_int::get(ty, 0xFFFFFFFF);
  if(ty->is_floating_point_ty())
    return constant_fp::get(ty, 0xFFFFFFFF);
  throw std::runtime_error("Cannot create all ones value for that type!");
}

// constant_int
// FIXME use something like APInt

constant_int::constant_int(type *ty, uint64_t value)
  : constant(ty, 0), value_(value){ }

constant_int *constant_int::get(type *ty, uint64_t value) {
  context_impl *impl = ty->get_context().p_impl.get();
  constant_int *& cst = impl->int_constants_[std::make_pair(ty, value)];
  if(cst == nullptr)
    cst = new constant_int(ty, value);
  return cst;
}

// constant_fp
// FIXME use something like APFloat

constant_fp::constant_fp(type *ty, double value)
  : constant(ty, 0), value_(value){ }

constant *constant_fp::get_negative_zero(type *ty){
  double neg_zero = 0;
  return get(ty, neg_zero);
}

constant *constant_fp::get_zero_value_for_negation(type *ty) {
  if(ty->get_scalar_ty()->is_floating_point_ty())
    return constant_fp::get(ty, 0);
  return constant::get_null_value(ty);
}

constant *constant_fp::get(type *ty, double v){
  context_impl *impl = ty->get_context().p_impl.get();
  constant_fp *&result = impl->fp_constants_[std::make_pair(ty, v)];
  if(!result)
    result = new constant_fp(ty, v);
  return result;
}

// undef value
undef_value::undef_value(type *ty)
  : constant(ty, 0) { }

undef_value *undef_value::get(type *ty) {
  context_impl *impl = ty->get_context().p_impl.get();
  undef_value *&result = impl->uv_constants_[ty];
  if(!result)
    result = new undef_value(ty);
  return result;
}

/* global value */
global_value::global_value(type *ty, unsigned num_ops,
                           linkage_types_t linkage,
                           const std::string &name, unsigned addr_space)
    : constant(pointer_type::get(ty, addr_space), num_ops, name),
      linkage_(linkage) { }

/* global object */
global_object::global_object(type *ty, unsigned num_ops,
                            linkage_types_t linkage,
                            const std::string &name, unsigned addr_space)
  : global_value(ty, num_ops, linkage, name, addr_space) { }

/* alloc const */
alloc_const::alloc_const(type *ty, constant_int *size, const std::string &name)
  : global_object(ty, 1, global_value::external, name, 4) {
  set_operand(0, size);
}

}
}
<commit_msg>[IR] Check constant_int type<commit_after>#include <cassert>
#include "triton/ir/constant.h"
#include "triton/ir/type.h"
#include "triton/ir/context.h"
#include "triton/ir/context_impl.h"

namespace triton{
namespace ir{

// constant

constant *constant::get_null_value(type *ty) {
  context &ctx = ty->get_context();
  switch (ty->get_scalar_ty()->get_type_id()) {
  case type::IntegerTyID:
    return constant_int::get(ty, 0);
  case type::HalfTyID:
    return constant_fp::get(type::get_half_ty(ctx), 0);
  case type::FloatTyID:
    return constant_fp::get(type::get_float_ty(ctx), 0);
  case type::DoubleTyID:
    return constant_fp::get(type::get_double_ty(ctx), 0);
  default:
    throw std::runtime_error("Cannot create a null constant of that type!");
  }
}

// FIXME

constant *constant::get_all_ones_value(type *ty) {
  if(ty->is_integer_ty())
    return constant_int::get(ty, 0xFFFFFFFF);
  if(ty->is_floating_point_ty())
    return constant_fp::get(ty, 0xFFFFFFFF);
  throw std::runtime_error("Cannot create all ones value for that type!");
}

// constant_int
// FIXME use something like APInt

constant_int::constant_int(type *ty, uint64_t value)
  : constant(ty, 0), value_(value){ }

constant_int *constant_int::get(type *ty, uint64_t value) {
  if (!ty->is_integer_ty())
    throw std::runtime_error("Cannot create constant_int with non integer ty");
  context_impl *impl = ty->get_context().p_impl.get();
  constant_int *& cst = impl->int_constants_[std::make_pair(ty, value)];
  if(cst == nullptr)
    cst = new constant_int(ty, value);
  return cst;
}

// constant_fp
// FIXME use something like APFloat

constant_fp::constant_fp(type *ty, double value)
  : constant(ty, 0), value_(value){ }

constant *constant_fp::get_negative_zero(type *ty){
  double neg_zero = 0;
  return get(ty, neg_zero);
}

constant *constant_fp::get_zero_value_for_negation(type *ty) {
  if(ty->get_scalar_ty()->is_floating_point_ty())
    return constant_fp::get(ty, 0);
  return constant::get_null_value(ty);
}

constant *constant_fp::get(type *ty, double v){
  context_impl *impl = ty->get_context().p_impl.get();
  constant_fp *&result = impl->fp_constants_[std::make_pair(ty, v)];
  if(!result)
    result = new constant_fp(ty, v);
  return result;
}

// undef value
undef_value::undef_value(type *ty)
  : constant(ty, 0) { }

undef_value *undef_value::get(type *ty) {
  context_impl *impl = ty->get_context().p_impl.get();
  undef_value *&result = impl->uv_constants_[ty];
  if(!result)
    result = new undef_value(ty);
  return result;
}

/* global value */
global_value::global_value(type *ty, unsigned num_ops,
                           linkage_types_t linkage,
                           const std::string &name, unsigned addr_space)
    : constant(pointer_type::get(ty, addr_space), num_ops, name),
      linkage_(linkage) { }

/* global object */
global_object::global_object(type *ty, unsigned num_ops,
                            linkage_types_t linkage,
                            const std::string &name, unsigned addr_space)
  : global_value(ty, num_ops, linkage, name, addr_space) { }

/* alloc const */
alloc_const::alloc_const(type *ty, constant_int *size, const std::string &name)
  : global_object(ty, 1, global_value::external, name, 4) {
  set_operand(0, size);
}

}
}
<|endoftext|>


<commit_before>/*
 * Simple parser for CSS (Cascading Style Sheets).
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "css_parser.hxx"
#include "css_syntax.hxx"
#include "pool.hxx"
#include "istream/istream.hxx"
#include "util/CharUtil.hxx"
#include "util/TrivialArray.hxx"
#include "util/StringView.hxx"

enum CssParserState {
    CSS_PARSER_NONE,
    CSS_PARSER_BLOCK,
    CSS_PARSER_CLASS_NAME,
    CSS_PARSER_XML_ID,
    CSS_PARSER_DISCARD_QUOTED,
    CSS_PARSER_PROPERTY,
    CSS_PARSER_POST_PROPERTY,
    CSS_PARSER_PRE_VALUE,
    CSS_PARSER_VALUE,
    CSS_PARSER_PRE_URL,
    CSS_PARSER_URL,

    /**
     * An '@' was found.  Feeding characters into "name".
     */
    CSS_PARSER_AT,
    CSS_PARSER_PRE_IMPORT,
    CSS_PARSER_IMPORT,
};

struct CssParser {
    template<size_t max>
    class StringBuffer : public TrivialArray<char, max> {
    public:
        using TrivialArray<char, max>::capacity;
        using TrivialArray<char, max>::size;
        using TrivialArray<char, max>::raw;
        using TrivialArray<char, max>::end;

        size_t GetRemainingSpace() const {
            return capacity() - size();
        }

        void AppendTruncated(StringView p) {
            size_t n = std::min(p.size, GetRemainingSpace());
            std::copy_n(p.data, n, end());
            this->the_size += n;
        }

        constexpr operator struct strref() const {
            return {size(), raw()};
        }

        constexpr operator StringView() const {
            return {raw(), size()};
        }

        gcc_pure
        bool Equals(StringView other) const {
            return other.Equals(*this);
        }
    };

    struct pool *pool;

    bool block;

    struct istream *input;
    off_t position;

    const CssParserHandler *handler;
    void *handler_ctx;

    /* internal state */
    CssParserState state;

    char quote;

    off_t name_start;
    StringBuffer<64> name_buffer;

    StringBuffer<64> value_buffer;

    off_t url_start;
    StringBuffer<1024> url_buffer;

    CssParser(struct pool *pool, struct istream *input, bool block,
              const CssParserHandler *handler, void *handler_ctx);

    size_t Feed(const char *start, size_t length);
};

static const char *
skip_whitespace(const char *p, const char *end)
{
    while (p < end && IsWhitespaceOrNull(*p))
        ++p;

    return p;
}

gcc_pure
static bool
at_url_start(const char *p, size_t length)
{
    return length >= 4 && memcmp(p + length - 4, "url(", 4) == 0 &&
        (/* just url(): */ length == 4 ||
         /* url() after another token: */
         IsWhitespaceOrNull(p[length - 5]));
}

size_t
CssParser::Feed(const char *start, size_t length)
{
    assert(input != nullptr);
    assert(start != nullptr);
    assert(length > 0);

    const char *buffer = start, *end = start + length, *p;
    size_t nbytes;
    CssParserValue url;

    while (buffer < end) {
        switch (state) {
        case CSS_PARSER_NONE:
            do {
                switch (*buffer) {
                case '{':
                    /* start of block */
                    state = CSS_PARSER_BLOCK;

                    if (handler->block != nullptr)
                        handler->block(handler_ctx);
                    break;

                case '.':
                    if (handler->class_name != nullptr) {
                        state = CSS_PARSER_CLASS_NAME;
                        name_start = position + (off_t)(buffer - start) + 1;
                        name_buffer.clear();
                    }

                    break;

                case '#':
                    if (handler->xml_id != nullptr) {
                        state = CSS_PARSER_XML_ID;
                        name_start = position + (off_t)(buffer - start) + 1;
                        name_buffer.clear();
                    }

                    break;

                case '@':
                    if (handler->import != nullptr) {
                        state = CSS_PARSER_AT;
                        name_buffer.clear();
                    }

                    break;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_NONE);

            break;

        case CSS_PARSER_CLASS_NAME:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (!name_buffer.empty()) {
                        CssParserValue name = {
                            .start = name_start,
                            .end = position + (off_t)(buffer - start),
                        };

                        name.value = name_buffer;
                        handler->class_name(&name,handler_ctx);
                    }

                    state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_XML_ID:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (!name_buffer.empty()) {
                        CssParserValue name = {
                            .start = name_start,
                            .end = position + (off_t)(buffer - start),
                        };

                        name.value = name_buffer;
                        handler->xml_id(&name, handler_ctx);
                    }

                    state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_BLOCK:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ':':
                    /* colon introduces property value */
                    state = CSS_PARSER_PRE_VALUE;
                    name_buffer.clear();
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;

                default:
                    if (is_css_ident_start(*buffer) &&
                        handler->property_keyword != nullptr) {
                        state = CSS_PARSER_PROPERTY;
                        name_start = position + (off_t)(buffer - start);
                        name_buffer.clear();
                        name_buffer.push_back(*buffer);
                    }
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_BLOCK);
            break;

        case CSS_PARSER_DISCARD_QUOTED:
            p = (const char *)memchr(buffer, quote, end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                position += (off_t)nbytes;
                return nbytes;
            }

            state = CSS_PARSER_BLOCK;
            buffer = p + 1;
            break;

        case CSS_PARSER_PROPERTY:
            while (buffer < end) {
                if (!is_css_ident_char(*buffer)) {
                    state = CSS_PARSER_POST_PROPERTY;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            }

            break;

        case CSS_PARSER_POST_PROPERTY:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ':':
                    /* colon introduces property value */
                    state = CSS_PARSER_PRE_VALUE;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_BLOCK);
            break;

        case CSS_PARSER_PRE_VALUE:
            buffer = skip_whitespace(buffer, end);
            if (buffer < end) {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    ++buffer;
                    break;

                case ';':
                    state = CSS_PARSER_BLOCK;
                    ++buffer;
                    break;

                default:
                    state = CSS_PARSER_VALUE;
                    value_buffer.clear();
                }
            }

            break;

        case CSS_PARSER_VALUE:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ';':
                    if (!name_buffer.empty()) {
                        assert(handler->property_keyword != nullptr);

                        name_buffer.push_back('\0');
                        value_buffer.push_back('\0');

                        handler->property_keyword(name_buffer.raw(),
                                                  value_buffer.raw(),
                                                  name_start,
                                                  position + (off_t)(buffer - start) + 1,
                                                  handler_ctx);
                    }

                    state = CSS_PARSER_BLOCK;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;

                default:
                    if (value_buffer.full())
                        break;

                    value_buffer.push_back(*buffer);
                    if (handler->url != nullptr &&
                        at_url_start(value_buffer.raw(),
                                     value_buffer.size()))
                        state = CSS_PARSER_PRE_URL;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_VALUE);
            break;

        case CSS_PARSER_PRE_URL:
            buffer = skip_whitespace(buffer, end);
            if (buffer < end) {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    ++buffer;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_URL;
                    quote = *buffer++;
                    url_start = position + (off_t)(buffer - start);
                    url_buffer.clear();
                    break;

                default:
                    state = CSS_PARSER_BLOCK;
                }
            }

            break;

        case CSS_PARSER_URL:
            p = (const char *)memchr(buffer, quote, end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                url_buffer.AppendTruncated({buffer, nbytes});
                position += (off_t)nbytes;
                return nbytes;
            }

            /* found the end of the URL - copy the rest, and invoke
               the handler method "url()" */
            nbytes = p - buffer;
            url_buffer.AppendTruncated({buffer, nbytes});

            buffer = p + 1;
            state = CSS_PARSER_BLOCK;

            url.start = url_start;
            url.end = position + (off_t)(p - start);
            url.value = url_buffer;
            handler->url(&url, handler_ctx);
            if (input == nullptr)
                return 0;

            break;

        case CSS_PARSER_AT:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (name_buffer.Equals({"import", 6}))
                        state = CSS_PARSER_PRE_IMPORT;
                    else
                        state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_PRE_IMPORT:
            do {
                if (!IsWhitespaceOrNull(*buffer)) {
                    if (*buffer == '"') {
                        ++buffer;
                        state = CSS_PARSER_IMPORT;
                        url_start = position + (off_t)(buffer - start);
                        url_buffer.clear();
                    } else
                        state = CSS_PARSER_NONE;
                    break;
                }

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_IMPORT:
            p = (const char *)memchr(buffer, '"', end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                url_buffer.AppendTruncated({buffer, nbytes});
                position += (off_t)nbytes;
                return nbytes;
            }

            /* found the end of the URL - copy the rest, and invoke
               the handler method "import()" */
            nbytes = p - buffer;
            url_buffer.AppendTruncated({buffer, nbytes});

            buffer = p + 1;
            state = CSS_PARSER_NONE;

            url.start = url_start;
            url.end = position + (off_t)(p - start);
            url.value = url_buffer;
            handler->import(&url, handler_ctx);
            if (input == nullptr)
                return 0;

            break;
        }
    }

    assert(input != nullptr);

    position += length;
    return length;
}

/*
 * istream handler
 *
 */

static size_t
css_parser_input_data(const void *data, size_t length, void *ctx)
{
    CssParser *parser = (CssParser *)ctx;

    const ScopePoolRef ref(*parser->pool TRACE_ARGS);
    return parser->Feed((const char *)data, length);
}

static void
css_parser_input_eof(void *ctx)
{
    CssParser *parser = (CssParser *)ctx;

    assert(parser->input != nullptr);

    parser->input = nullptr;
    parser->handler->eof(parser->handler_ctx, parser->position);
    pool_unref(parser->pool);
}

static void
css_parser_input_abort(GError *error, void *ctx)
{
    CssParser *parser = (CssParser *)ctx;

    assert(parser->input != nullptr);

    parser->input = nullptr;
    parser->handler->error(error, parser->handler_ctx);
    pool_unref(parser->pool);
}

static const struct istream_handler css_parser_input_handler = {
    .data = css_parser_input_data,
    .eof = css_parser_input_eof,
    .abort = css_parser_input_abort,
};

/*
 * constructor
 *
 */

CssParser::CssParser(struct pool *_pool, struct istream *_input, bool _block,
                     const CssParserHandler *_handler,
                     void *_handler_ctx)
    :pool(_pool), block(_block), position(0),
     handler(_handler), handler_ctx(_handler_ctx),
     state(block ? CSS_PARSER_BLOCK : CSS_PARSER_NONE)
{
    istream_assign_handler(&input, _input,
                           &css_parser_input_handler, this,
                           0);
}

CssParser *
css_parser_new(struct pool *pool, struct istream *input, bool block,
               const CssParserHandler *handler, void *handler_ctx)
{
    assert(pool != nullptr);
    assert(input != nullptr);
    assert(handler != nullptr);
    assert(handler->eof != nullptr);
    assert(handler->error != nullptr);

    pool_ref(pool);

    return NewFromPool<CssParser>(*pool, pool, input, block,
                                  handler, handler_ctx);
}

void
css_parser_close(CssParser *parser)
{
    assert(parser != nullptr);
    assert(parser->input != nullptr);

    istream_close(parser->input);
    pool_unref(parser->pool);
}

void
css_parser_read(CssParser *parser)
{
    assert(parser != nullptr);
    assert(parser->input != nullptr);

    istream_read(parser->input);
}
<commit_msg>css_parser: use MakeIstreamHandler<commit_after>/*
 * Simple parser for CSS (Cascading Style Sheets).
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "css_parser.hxx"
#include "css_syntax.hxx"
#include "pool.hxx"
#include "istream/istream_oo.hxx"
#include "util/CharUtil.hxx"
#include "util/TrivialArray.hxx"
#include "util/StringView.hxx"

enum CssParserState {
    CSS_PARSER_NONE,
    CSS_PARSER_BLOCK,
    CSS_PARSER_CLASS_NAME,
    CSS_PARSER_XML_ID,
    CSS_PARSER_DISCARD_QUOTED,
    CSS_PARSER_PROPERTY,
    CSS_PARSER_POST_PROPERTY,
    CSS_PARSER_PRE_VALUE,
    CSS_PARSER_VALUE,
    CSS_PARSER_PRE_URL,
    CSS_PARSER_URL,

    /**
     * An '@' was found.  Feeding characters into "name".
     */
    CSS_PARSER_AT,
    CSS_PARSER_PRE_IMPORT,
    CSS_PARSER_IMPORT,
};

struct CssParser {
    template<size_t max>
    class StringBuffer : public TrivialArray<char, max> {
    public:
        using TrivialArray<char, max>::capacity;
        using TrivialArray<char, max>::size;
        using TrivialArray<char, max>::raw;
        using TrivialArray<char, max>::end;

        size_t GetRemainingSpace() const {
            return capacity() - size();
        }

        void AppendTruncated(StringView p) {
            size_t n = std::min(p.size, GetRemainingSpace());
            std::copy_n(p.data, n, end());
            this->the_size += n;
        }

        constexpr operator struct strref() const {
            return {size(), raw()};
        }

        constexpr operator StringView() const {
            return {raw(), size()};
        }

        gcc_pure
        bool Equals(StringView other) const {
            return other.Equals(*this);
        }
    };

    struct pool *pool;

    bool block;

    struct istream *input;
    off_t position;

    const CssParserHandler *handler;
    void *handler_ctx;

    /* internal state */
    CssParserState state;

    char quote;

    off_t name_start;
    StringBuffer<64> name_buffer;

    StringBuffer<64> value_buffer;

    off_t url_start;
    StringBuffer<1024> url_buffer;

    CssParser(struct pool *pool, struct istream *input, bool block,
              const CssParserHandler *handler, void *handler_ctx);

    size_t Feed(const char *start, size_t length);

    /* istream handler */

    size_t OnData(const void *data, size_t length) {
        const ScopePoolRef ref(*pool TRACE_ARGS);
        return Feed((const char *)data, length);
    }

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof() {
        assert(input != nullptr);

        input = nullptr;
        handler->eof(handler_ctx, position);
        pool_unref(pool);
    }

    void OnError(GError *error) {
        assert(input != nullptr);

        input = nullptr;
        handler->error(error, handler_ctx);
        pool_unref(pool);
    }
};

static const char *
skip_whitespace(const char *p, const char *end)
{
    while (p < end && IsWhitespaceOrNull(*p))
        ++p;

    return p;
}

gcc_pure
static bool
at_url_start(const char *p, size_t length)
{
    return length >= 4 && memcmp(p + length - 4, "url(", 4) == 0 &&
        (/* just url(): */ length == 4 ||
         /* url() after another token: */
         IsWhitespaceOrNull(p[length - 5]));
}

size_t
CssParser::Feed(const char *start, size_t length)
{
    assert(input != nullptr);
    assert(start != nullptr);
    assert(length > 0);

    const char *buffer = start, *end = start + length, *p;
    size_t nbytes;
    CssParserValue url;

    while (buffer < end) {
        switch (state) {
        case CSS_PARSER_NONE:
            do {
                switch (*buffer) {
                case '{':
                    /* start of block */
                    state = CSS_PARSER_BLOCK;

                    if (handler->block != nullptr)
                        handler->block(handler_ctx);
                    break;

                case '.':
                    if (handler->class_name != nullptr) {
                        state = CSS_PARSER_CLASS_NAME;
                        name_start = position + (off_t)(buffer - start) + 1;
                        name_buffer.clear();
                    }

                    break;

                case '#':
                    if (handler->xml_id != nullptr) {
                        state = CSS_PARSER_XML_ID;
                        name_start = position + (off_t)(buffer - start) + 1;
                        name_buffer.clear();
                    }

                    break;

                case '@':
                    if (handler->import != nullptr) {
                        state = CSS_PARSER_AT;
                        name_buffer.clear();
                    }

                    break;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_NONE);

            break;

        case CSS_PARSER_CLASS_NAME:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (!name_buffer.empty()) {
                        CssParserValue name = {
                            .start = name_start,
                            .end = position + (off_t)(buffer - start),
                        };

                        name.value = name_buffer;
                        handler->class_name(&name,handler_ctx);
                    }

                    state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_XML_ID:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (!name_buffer.empty()) {
                        CssParserValue name = {
                            .start = name_start,
                            .end = position + (off_t)(buffer - start),
                        };

                        name.value = name_buffer;
                        handler->xml_id(&name, handler_ctx);
                    }

                    state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_BLOCK:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ':':
                    /* colon introduces property value */
                    state = CSS_PARSER_PRE_VALUE;
                    name_buffer.clear();
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;

                default:
                    if (is_css_ident_start(*buffer) &&
                        handler->property_keyword != nullptr) {
                        state = CSS_PARSER_PROPERTY;
                        name_start = position + (off_t)(buffer - start);
                        name_buffer.clear();
                        name_buffer.push_back(*buffer);
                    }
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_BLOCK);
            break;

        case CSS_PARSER_DISCARD_QUOTED:
            p = (const char *)memchr(buffer, quote, end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                position += (off_t)nbytes;
                return nbytes;
            }

            state = CSS_PARSER_BLOCK;
            buffer = p + 1;
            break;

        case CSS_PARSER_PROPERTY:
            while (buffer < end) {
                if (!is_css_ident_char(*buffer)) {
                    state = CSS_PARSER_POST_PROPERTY;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            }

            break;

        case CSS_PARSER_POST_PROPERTY:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ':':
                    /* colon introduces property value */
                    state = CSS_PARSER_PRE_VALUE;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_BLOCK);
            break;

        case CSS_PARSER_PRE_VALUE:
            buffer = skip_whitespace(buffer, end);
            if (buffer < end) {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    ++buffer;
                    break;

                case ';':
                    state = CSS_PARSER_BLOCK;
                    ++buffer;
                    break;

                default:
                    state = CSS_PARSER_VALUE;
                    value_buffer.clear();
                }
            }

            break;

        case CSS_PARSER_VALUE:
            do {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    break;

                case ';':
                    if (!name_buffer.empty()) {
                        assert(handler->property_keyword != nullptr);

                        name_buffer.push_back('\0');
                        value_buffer.push_back('\0');

                        handler->property_keyword(name_buffer.raw(),
                                                  value_buffer.raw(),
                                                  name_start,
                                                  position + (off_t)(buffer - start) + 1,
                                                  handler_ctx);
                    }

                    state = CSS_PARSER_BLOCK;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_DISCARD_QUOTED;
                    quote = *buffer;
                    break;

                default:
                    if (value_buffer.full())
                        break;

                    value_buffer.push_back(*buffer);
                    if (handler->url != nullptr &&
                        at_url_start(value_buffer.raw(),
                                     value_buffer.size()))
                        state = CSS_PARSER_PRE_URL;
                }

                ++buffer;
            } while (buffer < end && state == CSS_PARSER_VALUE);
            break;

        case CSS_PARSER_PRE_URL:
            buffer = skip_whitespace(buffer, end);
            if (buffer < end) {
                switch (*buffer) {
                case '}':
                    /* end of block */
                    if (block)
                        break;

                    state = CSS_PARSER_NONE;
                    ++buffer;
                    break;

                case '\'':
                case '"':
                    state = CSS_PARSER_URL;
                    quote = *buffer++;
                    url_start = position + (off_t)(buffer - start);
                    url_buffer.clear();
                    break;

                default:
                    state = CSS_PARSER_BLOCK;
                }
            }

            break;

        case CSS_PARSER_URL:
            p = (const char *)memchr(buffer, quote, end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                url_buffer.AppendTruncated({buffer, nbytes});
                position += (off_t)nbytes;
                return nbytes;
            }

            /* found the end of the URL - copy the rest, and invoke
               the handler method "url()" */
            nbytes = p - buffer;
            url_buffer.AppendTruncated({buffer, nbytes});

            buffer = p + 1;
            state = CSS_PARSER_BLOCK;

            url.start = url_start;
            url.end = position + (off_t)(p - start);
            url.value = url_buffer;
            handler->url(&url, handler_ctx);
            if (input == nullptr)
                return 0;

            break;

        case CSS_PARSER_AT:
            do {
                if (!is_css_nmchar(*buffer)) {
                    if (name_buffer.Equals({"import", 6}))
                        state = CSS_PARSER_PRE_IMPORT;
                    else
                        state = CSS_PARSER_NONE;
                    break;
                }

                if (name_buffer.size() < name_buffer.capacity() - 1)
                    name_buffer.push_back(*buffer);

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_PRE_IMPORT:
            do {
                if (!IsWhitespaceOrNull(*buffer)) {
                    if (*buffer == '"') {
                        ++buffer;
                        state = CSS_PARSER_IMPORT;
                        url_start = position + (off_t)(buffer - start);
                        url_buffer.clear();
                    } else
                        state = CSS_PARSER_NONE;
                    break;
                }

                ++buffer;
            } while (buffer < end);

            break;

        case CSS_PARSER_IMPORT:
            p = (const char *)memchr(buffer, '"', end - buffer);
            if (p == nullptr) {
                nbytes = end - start;
                url_buffer.AppendTruncated({buffer, nbytes});
                position += (off_t)nbytes;
                return nbytes;
            }

            /* found the end of the URL - copy the rest, and invoke
               the handler method "import()" */
            nbytes = p - buffer;
            url_buffer.AppendTruncated({buffer, nbytes});

            buffer = p + 1;
            state = CSS_PARSER_NONE;

            url.start = url_start;
            url.end = position + (off_t)(p - start);
            url.value = url_buffer;
            handler->import(&url, handler_ctx);
            if (input == nullptr)
                return 0;

            break;
        }
    }

    assert(input != nullptr);

    position += length;
    return length;
}

/*
 * constructor
 *
 */

CssParser::CssParser(struct pool *_pool, struct istream *_input, bool _block,
                     const CssParserHandler *_handler,
                     void *_handler_ctx)
    :pool(_pool), block(_block), position(0),
     handler(_handler), handler_ctx(_handler_ctx),
     state(block ? CSS_PARSER_BLOCK : CSS_PARSER_NONE)
{
    istream_assign_handler(&input, _input,
                           &MakeIstreamHandler<CssParser>::handler, this,
                           0);
}

CssParser *
css_parser_new(struct pool *pool, struct istream *input, bool block,
               const CssParserHandler *handler, void *handler_ctx)
{
    assert(pool != nullptr);
    assert(input != nullptr);
    assert(handler != nullptr);
    assert(handler->eof != nullptr);
    assert(handler->error != nullptr);

    pool_ref(pool);

    return NewFromPool<CssParser>(*pool, pool, input, block,
                                  handler, handler_ctx);
}

void
css_parser_close(CssParser *parser)
{
    assert(parser != nullptr);
    assert(parser->input != nullptr);

    istream_close(parser->input);
    pool_unref(parser->pool);
}

void
css_parser_read(CssParser *parser)
{
    assert(parser != nullptr);
    assert(parser->input != nullptr);

    istream_read(parser->input);
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// Copyright 2015 Corey Toler-Franklin, University of Florida
// RayTracer.h
// Shades the objects in the scene based on information gathered by bouncing
// a ray in the scene and computing ray/surface intersections
//------------------------------------------------------------------------------

#include "RayTracer.h"
#include <assert.h>
#include <stdio.h>
#include <string>
#include "utilities.h"
#include "STImage.h"
#include "Shader.h"
#include "STColor4ub.h"
#include <ctime>
#include <cstdlib>
#include "Surface.h"
#include "Sphere.h"
#include "STVector2.h"
#include <algorithm>
#include <vector>

double const RayTracer::c2w[4][4] =
{
    {0.4, 0.2, -0.8, 0.0},
    {-0.4, 0.9, 0.0, 0.0},
    {0.8, 0.3, 0.4, 0.0},
    {5.4, 3.0, -1.0, 1.0}
};

RayTracer::RayTracer(void)
    : m_maxLevel            (20),
     m_intensityThreshold   (0.001)
{
    pShader = new Shader();
}

RayTracer::~RayTracer()
{

}

//------------------------------------------------
// Main raytracing algorithm
// Cast Ray, Compute Intersections, Shade pixel
//-----------------------------------------------
void RayTracer::Run(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode)
{

    // begin
    std::cout << "Running... " << std::endl;

    // Clock stuff for timing it!
    std::clock_t start;
    double duration;
    start = std::clock();
    //
    //std::vector photons = new vector;
    emitPhotons(pScene, imageSize,fName,mode);
    //

    raytrace(pScene, imageSize,fName,mode, NULL,NULL);

    // End the clock timer and get its duration
    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    // end
    std::cout << "DONE... (Elapsed time: " << duration * 1000 << " ms, hit: " << ((((double) numRaysHit) / ((double) numRays)) * 100) << "% (" << numRaysHit << " / " << numRays << "))" << std::endl;

    // save
    pImg->Save(fName);
    std::cout << "saved file " << fName.c_str() << std::endl;
}

RGBR_f RayTracer::Shade(Scene *pScene, Intersection *pIntersection)
{
    LightList* sceneLightList = pScene->GetLightList();
    SurfaceList* surfaceList = pScene->GetSurfaceList();
    STVector3 shadowOrigin = pIntersection->point;

    RGBR_f color = RGBR_f(20, 20, 20, 255);

    for (int l = 0; l < sceneLightList->size(); l++) {
        Light light = sceneLightList->at(l);

        STVector3 shadowDirection = light.GetPosition() - pIntersection->point;
        shadowDirection.Normalize();

        Ray ray = Ray();
        ray.SetOrigin(shadowOrigin);
        ray.SetDirection(shadowDirection);
        Intersection intersection;

        for (int s = 0; s < surfaceList->size(); s++) { // Iterate over surfaces
            Surface* surface = surfaceList->at(s);

            if (surface != pIntersection->surface) {

                if (surface->FindIntersection(ray, &intersection)) {
                    goto LightLoop;
                }
            }
        }

        color += pShader->Run(pIntersection, &shadowDirection, &light);

        LightLoop:
        continue;
    }

    return(color);
}

//------------------------------------------------------
// Always render with a minimum color so that the scene
// is not black
//------------------------------------------------------
bool RayTracer::MinimumColor(RGBR_f color)
{
    if((color.r  >= m_intensityThreshold) ||
       (color.g >= m_intensityThreshold) ||
       (color.b >= m_intensityThreshold)) {
        return(true);
    }

    return(false);
}

void Raytracer::raytrace(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode, STVector3 origin, STVector3 direction){
// the color redult from shading
    RGBR_f color;

    // set the shader's render mode
    pShader->SetMode(mode);

    SurfaceList* surfaceList = pScene->GetSurfaceList();

    int width = imageSize->x;
    int height = imageSize->y;
    RGBR_f bkground = pScene->GetBackgroundColor();
    STImage *pImg = new STImage(width, height, STImage::Pixel(bkground.r*255, bkground.g*255, bkground.b*255, bkground.a*255));

    double aspectRatio = ((double) width) / ((double) height);
    double scale = tan(((double) pScene->GetCamera()->GetFov()) / 2.0 * M_PI / 180);

    // STVector3 rayOrigin = pScene->GetCamera()->GetPosition(); // Perspective

    /*STVector3 imagePoint = widthD * pScene->GetCamera()->Right() +
                    heightD * pScene->GetCamera()->Up() +
                    pScene->GetCamera()->Position() + pScene->GetCamera()->LookAt();*/

    STVector3 rayDirection(0, 0, 1); // Orthagonal
    STVector3 rayOrigin;
    int numRaysHit = 0;
    int numRays = 0;

    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            double pX = (2.0 * ((((double) i) + 0.5) / width) - 1.0) * scale * aspectRatio; // Perspective
            double pY = (1.0 - 2.0 * ((((double) j) + 0.5) / height)) * scale; // Perspective

                if(origin == NULL){
                    rayOrigin = pX * pScene->GetCamera()->Right() +
                    pY * pScene->GetCamera()->Up() +
                    pScene->GetCamera()->Position() + pScene->GetCamera()->LookAt();
                }else{
                    rayOrigin =origin;
                }

                if(direction == NULL){
                    STVector3 newDirection =rayOrigin - pScene->GetCamera()->Position();
                 }else{
                    rayDirection =direction;
                }
            //STVector3 rayDirection = rayOrigin - pScene->GetCamera()->Position();
            rayDirection.Normalize();

            Ray ray = Ray();
            ray.SetOrigin(rayOrigin);
            ray.SetDirection(rayDirection);

            Intersection* closestIntersection = NULL;

            for (int k = 0; k < surfaceList->size(); k++) {
                Intersection* returnIntersection = new Intersection();
                Surface* surface = (*surfaceList)[k];

                bool result = surface->FindIntersection(ray, returnIntersection);

                if (result) {
                    numRaysHit++;

                    if (closestIntersection == NULL) {
                        closestIntersection = returnIntersection;
                    } else if (returnIntersection->distanceSqu < closestIntersection->distanceSqu) {
                        delete closestIntersection;
                        closestIntersection = returnIntersection;
                    }
                } else {
                    delete returnIntersection;
                }

                numRays++;
            }

            if (closestIntersection != NULL) { // We hit something! calculate the pixel color at that point
                RGBR_f color = Shade(pScene, closestIntersection);
                int clamped_r = std::max(0.0f, std::min(color.r, 255.0f));
                int clamped_g = std::max(0.0f, std::min(color.g, 255.0f));
                int clamped_b = std::max(0.0f, std::min(color.b, 255.0f));
                pImg->SetPixel(i, j, STImage::Pixel(clamped_r, clamped_g, clamped_b, 255));
            }
        }
    }

}

void RayTracer::emitPhotons(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode){
//  randomSeed(0);                             //Ensure Same Photons Each Time
  for (int t = 0; t < nrTypes; t++)            //Initialize Photon Count to Zero for Each Object
    for (int i = 0; i < nrObjects[t]; i++)
      numPhotons[t][i] = 0;

  for (int i = 0; i < nrPhotons; i++){
    int bounces = 1;
    Photon photon(RGBR_f rgb(255.0,255.0,255.0,255.0),normalize3( rand3(1.0) ),normalize3( rand3(1.0) ));// continue work from here.  need to save photons somehow
    RGBR_f rgb(255.0,255.0,255.0,255.0);               //Initial Photon Color is White
    STVector3 direction = normalize3( rand3(1.0) );    //Randomize Direction of Photon Emission
    STVector3 origin = Light;                 //Emit From Point Light Source

    //Spread Out Light Source, But Don't Allow Photons Outside Room/Inside Sphere
    while (prevPoint[1] >= Light[1]){ prevPoint = add3(Light, mul3c(normalize3(rand3(1.0)), 0.75));}
    if (abs(prevPoint[0]) > 1.5 || abs(prevPoint[1]) > 1.2 ) bounces = nrBounces+1;

    raytrace(pScene,imageSize,fName,mode,origin, direction);                          //Trace the Photon's Path

    while (gIntersect && bounces <= nrBounces){        //Intersection With New Object
        gPoint = add3( mul3c(ray,gDist), prevPoint);   //3D Point of Intersection
        rgb = mul3c (getColor(rgb,gType,gIndex), 1.0/sqrt(bounces));
        storePhoton(gType, gIndex, gPoint, ray, rgb);  //Store Photon Info
        drawPhoton(rgb, gPoint);                       //Draw Photon
        shadowPhoton(ray);                             //Shadow Photon
        ray = reflect(ray,prevPoint);                  //Bounce the Photon
        raytrace(ray, gPoint);                         //Trace It to Next Location
        prevPoint = gPoint;
        bounces++;
    }
  }
}

STVector3 RayTracer::multVectMatrix(STVector3 rayOrigin) {

    STVector3 output;

}<commit_msg>just work<commit_after>//------------------------------------------------------------------------------
// Copyright 2015 Corey Toler-Franklin, University of Florida
// RayTracer.h
// Shades the objects in the scene based on information gathered by bouncing
// a ray in the scene and computing ray/surface intersections
//------------------------------------------------------------------------------

#include "RayTracer.h"
#include <assert.h>
#include <stdio.h>
#include <string>
#include "utilities.h"
#include "STImage.h"
#include "Shader.h"
#include "STColor4ub.h"
#include <ctime>
#include <cstdlib>
#include "Surface.h"
#include "Sphere.h"
#include "STVector2.h"
#include <algorithm>
#include <vector>
#include <stdlib.h>
double const RayTracer::c2w[4][4] =
{
    {0.4, 0.2, -0.8, 0.0},
    {-0.4, 0.9, 0.0, 0.0},
    {0.8, 0.3, 0.4, 0.0},
    {5.4, 3.0, -1.0, 1.0}
};

RayTracer::RayTracer(void)
    : m_maxLevel            (20),
     m_intensityThreshold   (0.001)
{
    pShader = new Shader();
}

RayTracer::~RayTracer()
{

}

//------------------------------------------------
// Main raytracing algorithm
// Cast Ray, Compute Intersections, Shade pixel
//-----------------------------------------------
void RayTracer::Run(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode)
{

    // begin
    std::cout << "Running... " << std::endl;

    // Clock stuff for timing it!
    std::clock_t start;
    double duration;
    start = std::clock();
    //
    //std::vector photons = new vector;
    emitPhotons(pScene, imageSize,fName,mode);
    //

    raytrace(pScene, imageSize,fName,mode, NULL,NULL);

    // End the clock timer and get its duration
    duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;

    // end
    std::cout << "DONE... (Elapsed time: " << duration * 1000 << " ms, hit: " << ((((double) numRaysHit) / ((double) numRays)) * 100) << "% (" << numRaysHit << " / " << numRays << "))" << std::endl;

    // save
    pImg->Save(fName);
    std::cout << "saved file " << fName.c_str() << std::endl;
}

RGBR_f RayTracer::Shade(Scene *pScene, Intersection *pIntersection)
{
    LightList* sceneLightList = pScene->GetLightList();
    SurfaceList* surfaceList = pScene->GetSurfaceList();
    STVector3 shadowOrigin = pIntersection->point;

    RGBR_f color = RGBR_f(20, 20, 20, 255);

    for (int l = 0; l < sceneLightList->size(); l++) {
        Light light = sceneLightList->at(l);

        STVector3 shadowDirection = light.GetPosition() - pIntersection->point;
        shadowDirection.Normalize();

        Ray ray = Ray();
        ray.SetOrigin(shadowOrigin);
        ray.SetDirection(shadowDirection);
        Intersection intersection;

        for (int s = 0; s < surfaceList->size(); s++) { // Iterate over surfaces
            Surface* surface = surfaceList->at(s);

            if (surface != pIntersection->surface) {

                if (surface->FindIntersection(ray, &intersection)) {
                    goto LightLoop;
                }
            }
        }

        color += pShader->Run(pIntersection, &shadowDirection, &light);

        LightLoop:
        continue;
    }

    return(color);
}

//------------------------------------------------------
// Always render with a minimum color so that the scene
// is not black
//------------------------------------------------------
bool RayTracer::MinimumColor(RGBR_f color)
{
    if((color.r  >= m_intensityThreshold) ||
       (color.g >= m_intensityThreshold) ||
       (color.b >= m_intensityThreshold)) {
        return(true);
    }

    return(false);
}

void Raytracer::raytrace(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode, STVector3 origin, STVector3 direction){
// the color redult from shading
    RGBR_f color;

    // set the shader's render mode
    pShader->SetMode(mode);

    SurfaceList* surfaceList = pScene->GetSurfaceList();

    int width = imageSize->x;
    int height = imageSize->y;
    RGBR_f bkground = pScene->GetBackgroundColor();
    STImage *pImg = new STImage(width, height, STImage::Pixel(bkground.r*255, bkground.g*255, bkground.b*255, bkground.a*255));

    double aspectRatio = ((double) width) / ((double) height);
    double scale = tan(((double) pScene->GetCamera()->GetFov()) / 2.0 * M_PI / 180);

    // STVector3 rayOrigin = pScene->GetCamera()->GetPosition(); // Perspective

    /*STVector3 imagePoint = widthD * pScene->GetCamera()->Right() +
                    heightD * pScene->GetCamera()->Up() +
                    pScene->GetCamera()->Position() + pScene->GetCamera()->LookAt();*/

    STVector3 rayDirection(0, 0, 1); // Orthagonal
    STVector3 rayOrigin;
    int numRaysHit = 0;
    int numRays = 0;

    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            double pX = (2.0 * ((((double) i) + 0.5) / width) - 1.0) * scale * aspectRatio; // Perspective
            double pY = (1.0 - 2.0 * ((((double) j) + 0.5) / height)) * scale; // Perspective

                if(origin == NULL){
                    rayOrigin = pX * pScene->GetCamera()->Right() +
                    pY * pScene->GetCamera()->Up() +
                    pScene->GetCamera()->Position() + pScene->GetCamera()->LookAt();
                }else{
                    rayOrigin =origin;
                }

                if(direction == NULL){
                    STVector3 newDirection =rayOrigin - pScene->GetCamera()->Position();
                 }else{
                    rayDirection =direction;
                }
            //STVector3 rayDirection = rayOrigin - pScene->GetCamera()->Position();
            rayDirection.Normalize();

            Ray ray = Ray();
            ray.SetOrigin(rayOrigin);
            ray.SetDirection(rayDirection);

            Intersection* closestIntersection = NULL;

            for (int k = 0; k < surfaceList->size(); k++) {
                Intersection* returnIntersection = new Intersection();
                Surface* surface = (*surfaceList)[k];

                bool result = surface->FindIntersection(ray, returnIntersection);

                if (result) {
                    numRaysHit++;

                    if (closestIntersection == NULL) {
                        closestIntersection = returnIntersection;
                    } else if (returnIntersection->distanceSqu < closestIntersection->distanceSqu) {
                        delete closestIntersection;
                        closestIntersection = returnIntersection;
                    }
                } else {
                    delete returnIntersection;
                }

                numRays++;
            }

            if (closestIntersection != NULL) { // We hit something! calculate the pixel color at that point
                RGBR_f color = Shade(pScene, closestIntersection);
                int clamped_r = std::max(0.0f, std::min(color.r, 255.0f));
                int clamped_g = std::max(0.0f, std::min(color.g, 255.0f));
                int clamped_b = std::max(0.0f, std::min(color.b, 255.0f));
                pImg->SetPixel(i, j, STImage::Pixel(clamped_r, clamped_g, clamped_b, 255));
            }
        }
    }

}

void RayTracer::emitPhotons(Scene *pScene, STVector2* imageSize, std::string fName, RenderMode mode){
//  randomSeed(0);
    srand (0);                          //Ensure Same Photons Each Time
  for (int t = 0; t < nrTypes; t++)            //Initialize Photon Count to Zero for Each Object
    for (int i = 0; i < nrObjects[t]; i++)
      numPhotons[t][i] = 0;

  for (int i = 0; i < nrPhotons; i++){
    int bounces = 1;
    Photon photon(RGBR_f rgb(255.0,255.0,255.0,255.0),normalize3( rand() % 1 - 1 ),normalize3( rand() % 1 - 1 ));// continue work from here.  need to save photons somehow
   // RGBR_f rgb(255.0,255.0,255.0,255.0);               //Initial Photon Color is White
   // STVector3 direction = normalize3( rand3(1.0) );    //Randomize Direction of Photon Emission
    //STVector3 origin = Light;                 //Emit From Point Light Source

    //Spread Out Light Source, But Don't Allow Photons Outside Room/Inside Sphere
    while (prevPoint[1] >= Light[1]){ prevPoint = add3(Light, mul3c(normalize3(rand3(1.0)), 0.75));}
    if (abs(prevPoint[0]) > 1.5 || abs(prevPoint[1]) > 1.2 ) bounces = nrBounces+1;

    raytrace(pScene,imageSize,fName,mode,origin, direction);                          //Trace the Photon's Path

    while (gIntersect && bounces <= nrBounces){        //Intersection With New Object
        gPoint = add3( mul3c(ray,gDist), prevPoint);   //3D Point of Intersection
        rgb = mul3c (getColor(rgb,gType,gIndex), 1.0/sqrt(bounces));
        storePhoton(gType, gIndex, gPoint, ray, rgb);  //Store Photon Info
        drawPhoton(rgb, gPoint);                       //Draw Photon
        shadowPhoton(ray);                             //Shadow Photon
        ray = reflect(ray,prevPoint);                  //Bounce the Photon
        raytrace(ray, gPoint);                         //Trace It to Next Location
        prevPoint = gPoint;
        bounces++;
    }
  }
}

STVector3 RayTracer::multVectMatrix(STVector3 rayOrigin) {

    STVector3 output;

}<|endoftext|>


<commit_before>#ifndef LUNAR_SPIN_LOCK_HPP
#define LUNAR_SPIN_LOCK_HPP

namespace lunar {

class spin_lock_ac;

class spin_lock {
public:
    spin_lock() : m_lock(0) { }
    ~spin_lock() { }

private:
    volatile int m_lock;

    friend class spin_lock_acquire;
    friend class spin_lock_acquire_unsafe;
};

class spin_lock_acquire {
public:
    spin_lock_acquire(spin_lock &lock) : m_spin_lock(lock)
    {
        while (__sync_lock_test_and_set(&lock.m_lock, 1)) {
            while (lock.m_lock) ;
            // busy-wait
        }
    }

    ~spin_lock_acquire()
    {
        __sync_lock_release(&m_spin_lock.m_lock);
    }

private:
    spin_lock &m_spin_lock;
};

class spin_lock_acquire_unsafe {
public:
    spin_lock_acquire_unsafe(spin_lock &lock) : m_spin_lock(lock)
    {
        while (__sync_lock_test_and_set(&lock.m_lock, 1)) {
            while (lock.m_lock) ;
            // busy-wait
        }
    }

    void unlock()
    {
        __sync_lock_release(&m_spin_lock.m_lock);
    }

private:
    spin_lock &m_spin_lock;
};

}

#endif // LUNAR_SPIN_LOCK_HPP
<commit_msg>use mm_pause in spin lcok<commit_after>#ifndef LUNAR_SPIN_LOCK_HPP
#define LUNAR_SPIN_LOCK_HPP

#include "lunar_rtm_lock.hpp"

namespace lunar {

class spin_lock_ac;

class spin_lock {
public:
    spin_lock() : m_lock(0) { }
    ~spin_lock() { }

private:
    volatile int m_lock;

    friend class spin_lock_acquire;
    friend class spin_lock_acquire_unsafe;
};

class spin_lock_acquire {
public:
    spin_lock_acquire(spin_lock &lock) : m_spin_lock(lock)
    {
        while (__sync_lock_test_and_set(&lock.m_lock, 1)) {
            while (lock.m_lock)
                _MM_PAUSE(); // busy-wait
        }
    }

    ~spin_lock_acquire()
    {
        __sync_lock_release(&m_spin_lock.m_lock);
    }

private:
    spin_lock &m_spin_lock;
};

class spin_lock_acquire_unsafe {
public:
    spin_lock_acquire_unsafe(spin_lock &lock) : m_spin_lock(lock)
    {
        while (__sync_lock_test_and_set(&lock.m_lock, 1)) {
            while (lock.m_lock)
                _MM_PAUSE(); // busy-wait
        }
    }

    void unlock()
    {
        __sync_lock_release(&m_spin_lock.m_lock);
    }

private:
    spin_lock &m_spin_lock;
};

}

#endif // LUNAR_SPIN_LOCK_HPP
<|endoftext|>