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

#include "chrome/browser/ui/views/frame/app_non_client_frame_view_aura.h"

#include "base/debug/stack_trace.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "grit/ui_resources.h"
#include "ui/aura/window.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/base/hit_test.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/compositor/layer.h"
#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"

namespace {
// The number of pixels to use as a hover zone at the top of the screen.
const int kTopMargin = 1;
// How long the hover animation takes if uninterrupted.
const int kHoverFadeDurationMs = 130;
// The number of pixels within the shadow to draw the buttons.
const int kShadowStart = 28;
}

class AppNonClientFrameViewAura::ControlView
    : public views::View, public views::ButtonListener {
 public:
  explicit ControlView(AppNonClientFrameViewAura* owner) :
      owner_(owner),
      close_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_CLOSE)),
      restore_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_RESTORE)) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    separator_ =
        *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SEPARATOR).ToSkBitmap();
    shadow_ = *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToSkBitmap();
    AddChildView(close_button_);
    AddChildView(restore_button_);
  }

  virtual void Layout() OVERRIDE {
    restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
    close_button_->SetPosition(
        gfx::Point(kShadowStart + close_button_->width() + separator_.width(),
                   0));
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(shadow_.width(), shadow_.height());
  }

  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    views::View::OnPaint(canvas);
    canvas->DrawBitmapInt(
        separator_, restore_button_->x() + restore_button_->width(), 0);
    canvas->DrawBitmapInt(shadow_, 0, 0);
  }

  void ButtonPressed(
      views::Button* sender,
      const views::Event& event) OVERRIDE {
    if (sender == close_button_)
      owner_->Close();
    else if (sender == restore_button_)
      owner_->Restore();
  }

 private:
  // Gets an image representing 3 bitmaps laid out horizontally that will be
  // used as the normal, hot and pushed states for the created button.
  views::ImageButton* CreateImageButton(int resource_id) {
    views::ImageButton* button = new views::ImageButton(this);
    const SkBitmap* all_images =
        ResourceBundle::GetSharedInstance().GetImageNamed(
            resource_id).ToSkBitmap();
    int width = all_images->width() / 3;
    int height = all_images->height();

    SkBitmap normal, hot, pushed;
    all_images->extractSubset(
        &normal,
        SkIRect::MakeXYWH(0, 0, width, height));
    all_images->extractSubset(
        &hot,
        SkIRect::MakeXYWH(width, 0, width, height));
    all_images->extractSubset(
        &pushed,
        SkIRect::MakeXYWH(2 * width, 0, width, height));
    button->SetImage(views::CustomButton::BS_NORMAL, &normal);
    button->SetImage(views::CustomButton::BS_HOT, &hot);
    button->SetImage(views::CustomButton::BS_PUSHED, &pushed);

    button->SizeToPreferredSize();
    return button;
  }

  AppNonClientFrameViewAura* owner_;
  views::ImageButton* close_button_;
  views::ImageButton* restore_button_;
  SkBitmap separator_;
  SkBitmap shadow_;

  DISALLOW_COPY_AND_ASSIGN(ControlView);
};

class AppNonClientFrameViewAura::Host : public views::MouseWatcherHost {
 public:
  explicit Host(AppNonClientFrameViewAura* owner) : owner_(owner) {}
  virtual ~Host() {}

  virtual bool Contains(
      const gfx::Point& screen_point,
      views::MouseWatcherHost::MouseEventType type) {
    gfx::Rect top_margin = owner_->GetScreenBounds();
    top_margin.set_height(kTopMargin);
    gfx::Rect control_bounds = owner_->GetControlBounds();
    control_bounds.Inset(kShadowStart, 0, 0, kShadowStart);
    return top_margin.Contains(screen_point) ||
        control_bounds.Contains(screen_point);
  }

  AppNonClientFrameViewAura* owner_;

  DISALLOW_COPY_AND_ASSIGN(Host);
};

AppNonClientFrameViewAura::AppNonClientFrameViewAura(
    BrowserFrame* frame, BrowserView* browser_view)
    : BrowserNonClientFrameView(frame, browser_view),
      control_view_(new ControlView(this)),
      control_widget_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          mouse_watcher_(new Host(this), this)) {
}

AppNonClientFrameViewAura::~AppNonClientFrameViewAura() {
}

gfx::Rect AppNonClientFrameViewAura::GetBoundsForClientView() const {
  gfx::Rect bounds = GetLocalBounds();
  bounds.Inset(0, kTopMargin, 0,  0);
  return bounds;
}

gfx::Rect AppNonClientFrameViewAura::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  gfx::Rect bounds = client_bounds;
  bounds.Inset(0, -kTopMargin, 0, 0);
  return bounds;
}

int AppNonClientFrameViewAura::NonClientHitTest(
    const gfx::Point& point) {
  return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
}

void AppNonClientFrameViewAura::GetWindowMask(const gfx::Size& size,
                                              gfx::Path* window_mask) {
}

void AppNonClientFrameViewAura::ResetWindowControls() {
}

void AppNonClientFrameViewAura::UpdateWindowIcon() {
}

gfx::Rect AppNonClientFrameViewAura::GetBoundsForTabStrip(
    views::View* tabstrip) const {
  return gfx::Rect();
}

int AppNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset(
    bool restored) const {
  return 0;
}

void AppNonClientFrameViewAura::UpdateThrobber(bool running) {
}

void AppNonClientFrameViewAura::OnMouseEntered(
    const views::MouseEvent& event) {
  if (!control_widget_) {
    control_widget_ = new views::Widget;
    views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
    params.parent = browser_view()->GetNativeHandle();
    params.transparent = true;
    control_widget_->Init(params);
    control_widget_->SetContentsView(control_view_);
    aura::Window* window = control_widget_->GetNativeView();
    gfx::Rect control_bounds = GetControlBounds();
    control_bounds.set_y(control_bounds.y() - control_bounds.height());
    window->SetBounds(control_bounds);
    control_widget_->Show();
  }

  ui::Layer* layer = control_widget_->GetNativeView()->layer();
  ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
  scoped_setter.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(kHoverFadeDurationMs));
  layer->SetBounds(GetControlBounds());
  layer->SetOpacity(1);

  mouse_watcher_.Start();
}

void AppNonClientFrameViewAura::MouseMovedOutOfHost() {
  ui::Layer* layer = control_widget_->GetNativeView()->layer();

  ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
  scoped_setter.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(kHoverFadeDurationMs));
  gfx::Rect control_bounds = GetControlBounds();
  control_bounds.set_y(control_bounds.y() - control_bounds.height());
  layer->SetBounds(control_bounds);
  layer->SetOpacity(0);
}

gfx::Rect AppNonClientFrameViewAura::GetControlBounds() const {
  gfx::Size preferred = control_view_->GetPreferredSize();
  gfx::Point location(width() - preferred.width(), 0);
  ConvertPointToWidget(this, &location);
  return gfx::Rect(
      location.x(), location.y(),
      preferred.width(), preferred.height());
}

void AppNonClientFrameViewAura::Close() {
  if (control_widget_)
    control_widget_->Close();
  control_widget_ = NULL;
  mouse_watcher_.Stop();
  frame()->Close();
}

void AppNonClientFrameViewAura::Restore() {
  if (control_widget_)
    control_widget_->Close();
  control_widget_ = NULL;
  mouse_watcher_.Stop();
  frame()->Restore();
}
<commit_msg>Create black background for full screen app windows BUG=118111 TEST=Visual<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/frame/app_non_client_frame_view_aura.h"

#include "base/debug/stack_trace.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "grit/ui_resources.h"
#include "ui/aura/window.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/base/hit_test.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/compositor/layer.h"
#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"

namespace {
// The number of pixels to use as a hover zone at the top of the screen.
const int kTopMargin = 1;
// How long the hover animation takes if uninterrupted.
const int kHoverFadeDurationMs = 130;
// The number of pixels within the shadow to draw the buttons.
const int kShadowStart = 28;
}

class AppNonClientFrameViewAura::ControlView
    : public views::View, public views::ButtonListener {
 public:
  explicit ControlView(AppNonClientFrameViewAura* owner) :
      owner_(owner),
      close_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_CLOSE)),
      restore_button_(CreateImageButton(IDR_AURA_WINDOW_FULLSCREEN_RESTORE)) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    separator_ =
        *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SEPARATOR).ToSkBitmap();
    shadow_ = *rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToSkBitmap();
    AddChildView(close_button_);
    AddChildView(restore_button_);
  }

  virtual void Layout() OVERRIDE {
    restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
    close_button_->SetPosition(
        gfx::Point(kShadowStart + close_button_->width() + separator_.width(),
                   0));
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(shadow_.width(), shadow_.height());
  }

  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    views::View::OnPaint(canvas);
    canvas->DrawBitmapInt(
        separator_, restore_button_->x() + restore_button_->width(), 0);
    canvas->DrawBitmapInt(shadow_, 0, 0);
  }

  void ButtonPressed(
      views::Button* sender,
      const views::Event& event) OVERRIDE {
    if (sender == close_button_)
      owner_->Close();
    else if (sender == restore_button_)
      owner_->Restore();
  }

 private:
  // Gets an image representing 3 bitmaps laid out horizontally that will be
  // used as the normal, hot and pushed states for the created button.
  views::ImageButton* CreateImageButton(int resource_id) {
    views::ImageButton* button = new views::ImageButton(this);
    const SkBitmap* all_images =
        ResourceBundle::GetSharedInstance().GetImageNamed(
            resource_id).ToSkBitmap();
    int width = all_images->width() / 3;
    int height = all_images->height();

    SkBitmap normal, hot, pushed;
    all_images->extractSubset(
        &normal,
        SkIRect::MakeXYWH(0, 0, width, height));
    all_images->extractSubset(
        &hot,
        SkIRect::MakeXYWH(width, 0, width, height));
    all_images->extractSubset(
        &pushed,
        SkIRect::MakeXYWH(2 * width, 0, width, height));
    button->SetImage(views::CustomButton::BS_NORMAL, &normal);
    button->SetImage(views::CustomButton::BS_HOT, &hot);
    button->SetImage(views::CustomButton::BS_PUSHED, &pushed);

    button->SizeToPreferredSize();
    return button;
  }

  AppNonClientFrameViewAura* owner_;
  views::ImageButton* close_button_;
  views::ImageButton* restore_button_;
  SkBitmap separator_;
  SkBitmap shadow_;

  DISALLOW_COPY_AND_ASSIGN(ControlView);
};

class AppNonClientFrameViewAura::Host : public views::MouseWatcherHost {
 public:
  explicit Host(AppNonClientFrameViewAura* owner) : owner_(owner) {}
  virtual ~Host() {}

  virtual bool Contains(
      const gfx::Point& screen_point,
      views::MouseWatcherHost::MouseEventType type) {
    gfx::Rect top_margin = owner_->GetScreenBounds();
    top_margin.set_height(kTopMargin);
    gfx::Rect control_bounds = owner_->GetControlBounds();
    control_bounds.Inset(kShadowStart, 0, 0, kShadowStart);
    return top_margin.Contains(screen_point) ||
        control_bounds.Contains(screen_point);
  }

  AppNonClientFrameViewAura* owner_;

  DISALLOW_COPY_AND_ASSIGN(Host);
};

AppNonClientFrameViewAura::AppNonClientFrameViewAura(
    BrowserFrame* frame, BrowserView* browser_view)
    : BrowserNonClientFrameView(frame, browser_view),
      control_view_(new ControlView(this)),
      control_widget_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          mouse_watcher_(new Host(this), this)) {
  set_background(views::Background::CreateSolidBackground(SK_ColorBLACK));
}

AppNonClientFrameViewAura::~AppNonClientFrameViewAura() {
}

gfx::Rect AppNonClientFrameViewAura::GetBoundsForClientView() const {
  gfx::Rect bounds = GetLocalBounds();
  bounds.Inset(0, kTopMargin, 0,  0);
  return bounds;
}

gfx::Rect AppNonClientFrameViewAura::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  gfx::Rect bounds = client_bounds;
  bounds.Inset(0, -kTopMargin, 0, 0);
  return bounds;
}

int AppNonClientFrameViewAura::NonClientHitTest(
    const gfx::Point& point) {
  return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
}

void AppNonClientFrameViewAura::GetWindowMask(const gfx::Size& size,
                                              gfx::Path* window_mask) {
}

void AppNonClientFrameViewAura::ResetWindowControls() {
}

void AppNonClientFrameViewAura::UpdateWindowIcon() {
}

gfx::Rect AppNonClientFrameViewAura::GetBoundsForTabStrip(
    views::View* tabstrip) const {
  return gfx::Rect();
}

int AppNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset(
    bool restored) const {
  return 0;
}

void AppNonClientFrameViewAura::UpdateThrobber(bool running) {
}

void AppNonClientFrameViewAura::OnMouseEntered(
    const views::MouseEvent& event) {
  if (!control_widget_) {
    control_widget_ = new views::Widget;
    views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
    params.parent = browser_view()->GetNativeHandle();
    params.transparent = true;
    control_widget_->Init(params);
    control_widget_->SetContentsView(control_view_);
    aura::Window* window = control_widget_->GetNativeView();
    gfx::Rect control_bounds = GetControlBounds();
    control_bounds.set_y(control_bounds.y() - control_bounds.height());
    window->SetBounds(control_bounds);
    control_widget_->Show();
  }

  ui::Layer* layer = control_widget_->GetNativeView()->layer();
  ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
  scoped_setter.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(kHoverFadeDurationMs));
  layer->SetBounds(GetControlBounds());
  layer->SetOpacity(1);

  mouse_watcher_.Start();
}

void AppNonClientFrameViewAura::MouseMovedOutOfHost() {
  ui::Layer* layer = control_widget_->GetNativeView()->layer();

  ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
  scoped_setter.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(kHoverFadeDurationMs));
  gfx::Rect control_bounds = GetControlBounds();
  control_bounds.set_y(control_bounds.y() - control_bounds.height());
  layer->SetBounds(control_bounds);
  layer->SetOpacity(0);
}

gfx::Rect AppNonClientFrameViewAura::GetControlBounds() const {
  gfx::Size preferred = control_view_->GetPreferredSize();
  gfx::Point location(width() - preferred.width(), 0);
  ConvertPointToWidget(this, &location);
  return gfx::Rect(
      location.x(), location.y(),
      preferred.width(), preferred.height());
}

void AppNonClientFrameViewAura::Close() {
  if (control_widget_)
    control_widget_->Close();
  control_widget_ = NULL;
  mouse_watcher_.Stop();
  frame()->Close();
}

void AppNonClientFrameViewAura::Restore() {
  if (control_widget_)
    control_widget_->Close();
  control_widget_ = NULL;
  mouse_watcher_.Stop();
  frame()->Restore();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <stdio.h>
#include <math.h>
typedef long long lld;

using namespace std;

int main(int argc, char* argv[]) {
    int n, m, x;
    cin >> n >> m;
    vector<int> need(n);
    for (int i = 0; i < n; ++i) {
        cin >> need[i];
    }
    vector<int> curr(m);
    for (int i = 0; i < m; ++i) {
        cin >> curr[i];
    }
    sort(need.begin(), need.end());
    sort(curr.begin(), curr.end());
    int ans = 0;
    for (int i = 0, p = 0; i < need.size(); ++i) {
        while (p < curr.size() && curr[p] < need[i]) {
            ++p;
        }
        if (p < curr.size() && curr[p] >= need[i]) {
            continue;
        }
        ++ans;
    }
    cout << ans << endl;
    return 0;
}

<commit_msg>Wrong answer on test 4: http://codeforces.com/contest/387/submission/5928442<commit_after>#include <stdio.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <list>
#include <map>
#include <algorithm>
#include <stdio.h>
#include <math.h>
typedef long long lld;

using namespace std;

int main(int argc, char* argv[]) {
    int n, m, x;
    cin >> n >> m;
    vector<int> need(n);
    for (int i = 0; i < n; ++i) {
        cin >> need[i];
    }
    vector<int> curr(m);
    for (int i = 0; i < m; ++i) {
        cin >> curr[i];
    }
    sort(need.begin(), need.end());
    sort(curr.begin(), curr.end());
    int ans = n;
    for (int i = 0, p = 0; i < need.size(); ++i) {
        while (p < curr.size() && curr[p] < need[i]) {
            ++p;
        }
        if (p < curr.size() && curr[p] >= need[i]) {
            --ans;
        }
    }
    cout << ans << endl;
    return 0;
}

<|endoftext|>


<commit_before>#include "util.h"

uint8_t lastError = ERROR_NONE;

// bringt den Chip in den Fehler-Modus und blockiert ihn
void error(const char* tag, const char* message, boolean blinkFast)
{
	writeEEPROM("fError");
	writeEEPROM(message);

	serialPrintF("error(tag = ");
	serialPrint(tag);
	serialPrintF(", message = ");
	serialPrint(message);
	serialPrintlnF(")");

	while (true) {
		toogleRedLed();

		if (blinkFast)
			delay(250);
		else
			delay(500);
		wdt_yield();
	}
}

void internalError()
{
	internalError(ERROR_INTERNAL);
}

void internalError(uint8_t error)
{
	writeEEPROM("iError");
	writeEEPROM(error);

	wdt_yield();
	serialPrintF("Error(error = ");
	serialPrint(error);
	serialPrintlnF(")");

	lastError = error;
	blinkRedLedShort(true);
}

void protocolError(uint8_t error)
{
	writeEEPROM("pError");
	writeEEPROM(error);

	wdt_yield();
	serialPrintF("protocolError(error = ");
	serialPrint(error);
	serialPrintlnF(")");

	lastError = error;
	blinkRedLedShort(true);
}

char getHexChar(int32_t x)
{
	x &= 0xF;
	if (x >= 10)
		return 'A' + (x - 10);
	return '0' + x;
}

unsigned long timersData[TIMER_COUNT];

void startTime(uint8_t index) {
	if (index >= TIMER_COUNT)
		return internalError(ERROR_INTERNAL_INVALID_TIMER);

	timersData[index] = micros();
}

int32_t endTime(uint8_t index) {
	if (index >= TIMER_COUNT) {
		internalError(ERROR_INTERNAL_INVALID_TIMER);
		return 0;
	}

	unsigned long end = micros();
	if (end > timersData[index])
		return end - timersData[index];
	return 0;
}

uint32_t freeRam() {
	// siehe http://playground.arduino.cc/Code/AvailableMemory
	extern int32_t __heap_start, *__brkval;
	int32_t v;
	return ((int32_t)&v - (__brkval == 0 ? (int32_t)&__heap_start : (int32_t)__brkval));
}

uint32_t logPosition = 16;

void initEEPROM()
{
	logPosition = 16;
}

void writeEEPROM(uint8_t value)
{
#if ENABLE_EEPROM_LOG
	logPosition = logPosition % 1000;
	while (!eeprom_is_ready())
		wdt_yield();

	_EEPUT(logPosition++, value);
#endif
	wdt_yield();
}

void writeEEPROM(const char * str)
{
	uint32_t len = strlen(str);

	for (uint32_t i = 0; i < len; i++)
		writeEEPROM((uint8_t)str[i]);

	writeEEPROM((uint8_t)' ');
}<commit_msg>Clear EEPROM in initEEPROM()<commit_after>#include "util.h"

uint8_t lastError = ERROR_NONE;

// bringt den Chip in den Fehler-Modus und blockiert ihn
void error(const char* tag, const char* message, boolean blinkFast)
{
	writeEEPROM("fError");
	writeEEPROM(message);

	serialPrintF("error(tag = ");
	serialPrint(tag);
	serialPrintF(", message = ");
	serialPrint(message);
	serialPrintlnF(")");

	while (true) {
		toogleRedLed();

		if (blinkFast)
			delay(250);
		else
			delay(500);
		wdt_yield();
	}
}

void internalError()
{
	internalError(ERROR_INTERNAL);
}

void internalError(uint8_t error)
{
	writeEEPROM("iError");
	writeEEPROM(error);

	wdt_yield();
	serialPrintF("Error(error = ");
	serialPrint(error);
	serialPrintlnF(")");

	lastError = error;
	blinkRedLedShort(true);
}

void protocolError(uint8_t error)
{
	writeEEPROM("pError");
	writeEEPROM(error);

	wdt_yield();
	serialPrintF("protocolError(error = ");
	serialPrint(error);
	serialPrintlnF(")");

	lastError = error;
	blinkRedLedShort(true);
}

char getHexChar(int32_t x)
{
	x &= 0xF;
	if (x >= 10)
		return 'A' + (x - 10);
	return '0' + x;
}

unsigned long timersData[TIMER_COUNT];

void startTime(uint8_t index) {
	if (index >= TIMER_COUNT)
		return internalError(ERROR_INTERNAL_INVALID_TIMER);

	timersData[index] = micros();
}

int32_t endTime(uint8_t index) {
	if (index >= TIMER_COUNT) {
		internalError(ERROR_INTERNAL_INVALID_TIMER);
		return 0;
	}

	unsigned long end = micros();
	if (end > timersData[index])
		return end - timersData[index];
	return 0;
}

uint32_t freeRam() {
	// siehe http://playground.arduino.cc/Code/AvailableMemory
	extern int32_t __heap_start, *__brkval;
	int32_t v;
	return ((int32_t)&v - (__brkval == 0 ? (int32_t)&__heap_start : (int32_t)__brkval));
}

#define DEFAULT_LOG_POSITION 16

uint32_t logPosition = DEFAULT_LOG_POSITION;

void initEEPROM()
{
	// Clear EEPROM
	logPosition = DEFAULT_LOG_POSITION;
	for (int i = 0; i < 200; i++)
		writeEEPROM((uint8_t)'?');
	logPosition = DEFAULT_LOG_POSITION;
}

void writeEEPROM(uint8_t value)
{
#if ENABLE_EEPROM_LOG
	logPosition = logPosition % 1000;
	while (!eeprom_is_ready())
		wdt_yield();

	_EEPUT(logPosition++, value);
#endif
	wdt_yield();
}

void writeEEPROM(const char * str)
{
	uint32_t len = strlen(str);

	for (uint32_t i = 0; i < len; i++)
		writeEEPROM((uint8_t)str[i]);

	writeEEPROM((uint8_t)' ');
}<|endoftext|>


<commit_before>#include <windows.h>

#include <gl\gl.h>

#include "Settings.h"
#include "Main.h"
#include "VideoBase.h"
#include "Loader.h"
#include "Window.h"
#include "Text.h"
#include "Info.h"
#include "Error.h"
#include "GamePlay.h"

#define SPLASH_RESOURCE NULL
#define SPLASH_FILE "SPLASH.JPG"

#define SPLASH_FONT_NAME "Arial"
#define SPLASH_FONT_SIZE_AT_H600 12
#define SPLASH_FONT_SIZE (SPLASH_FONT_SIZE_AT_H600*CWindow::GetHeight()/600)
#define SPLASH_TEXT_SPACING_COEFF 1.75f

#define SPLASH_TEXT_COLOR_R 0.75f
#define SPLASH_TEXT_COLOR_G 0.75f
#define SPLASH_TEXT_COLOR_B 0.75f

#define RESTART_ALLOWED true
#define RESTART_TIME 10.0f

int CGamePlay::splash_tex=0;
char CGamePlay::load_text[256];
CGamePlay::splash_rect CGamePlay::splash_pos;
CBody CGamePlay::mainbody;
CCamera CGamePlay::camera;
CStarMap CGamePlay::starmap;
CClock CGamePlay::clock;
CLensFlare CGamePlay::lensflare;
bool CGamePlay::flares=false;
bool CGamePlay::planetinfo=false;
CText CGamePlay::splashtext;
CInfo CGamePlay::info;

CGamePlay::CGamePlay()
{
}

CGamePlay::~CGamePlay()
{
}

bool CGamePlay::Init()
{
	bool ret=true;
	if (!splashtext.BuildFTFont(SPLASH_FONT_NAME,SPLASH_FONT_SIZE))
		CError::LogError(WARNING_CODE,"Failed to load the splash text font - ignoring.");
	if (!InitScene())
	{
		if (UserAbortedLoad())
			OnUserAbortLoad();
		else
			CError::LogError(ERROR_CODE,"Unable to load scene critical data - aborting.");
		DestroyScene();
		ret=false;
	}
	FreeSplash();
	splashtext.Free();
	return ret;
}

void CGamePlay::ShutDown()
{
	DestroyScene();
}

void CGamePlay::CalcSplashRect()
{
	int w=CWindow::GetWidth();
	int h=CWindow::GetHeight();
	splash_pos.x1=(w*3<=h*4?0:(w-h*4/3)/2);
	splash_pos.x2=(w*3<=h*4?w:(w+h*4/3)/2);
	splash_pos.y1=(w*3>=h*4?0:(h-w*3/4)/2);
	splash_pos.y2=(w*3>=h*4?h:(h+w*3/4)/2);
}

bool CGamePlay::LoadSplash()
{
	CalcSplashRect();
	CLoader loader;
	loader.WithResource(SPLASH_RESOURCE);
	splash_tex=loader.LoadTexture(SPLASH_FILE,NULL,CVideoBase::GetOptMipmaps(),CVideoBase::GetOptLinear());
	return (splash_tex>0);
}

void CGamePlay::FreeSplash()
{
	glDeleteTextures(1,(GLuint*)&splash_tex);
	splash_tex=0;
}

void CGamePlay::InitLight()
{
	GLfloat LightAmbient[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1,GL_AMBIENT,LightAmbient);
	glLightfv(GL_LIGHT1,GL_DIFFUSE,LightDiffuse);
	glLightfv(GL_LIGHT1,GL_SPECULAR,LightSpecular);
	glEnable(GL_LIGHT1);
}

void CGamePlay::OnUserAbortLoad()
{
	// log new error
	CError::LogError(ERROR_CODE,"User aborted load.");
	// get first error, and if it's "user abort", clear the log so it's not printed
	if (CError::ErrorsOccured())
	{
		int code;
		char string[ERROR_MAXLEN];
		CError::Rewind();
		CError::GetNextError(&code,string);
		strlwr(string);
		if (strstr(string,"user") && strstr(string,"abort"))
			CError::Clear();
	}
}

bool CGamePlay::UserAbortedLoad()
{
	static bool userabort=false;
	if (!userabort)
		userabort=!MessagePump();
	return userabort;
}

bool CGamePlay::InitScene()
{
	{
		SetSplashText("Loading splash screen... ");
		if (!LoadSplash())
			CError::LogError(WARNING_CODE,"Failed to load the splash screen - ignoring.");
	}

	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading bodies... ");
		if (!mainbody.Load())
		{
			CError::LogError(ERROR_CODE,"Failed to load the bodies - aborting.");
			return false;
		}
	}

	flares=CVideoBase::GetOptLensFlares();
	if (flares)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading lens flares... ");
		if (!lensflare.Load(&mainbody))
		{
			CError::LogError(WARNING_CODE,"Failed to load the lens flares - ignoring.");
			flares=false;
		}
	}

	planetinfo=(CSettings::PlanetInfo==TRUE);
	if (planetinfo)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading info text font... ");
		if (!info.Load())
		{
			CError::LogError(WARNING_CODE,"Failed to load the planet info - ignoring.");
			planetinfo=false;
		}
	}

	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading starmap... ");
		if (!starmap.Load())
			CError::LogError(WARNING_CODE,"Failed to load the starmap - ignoring.");
	}

	if (CSettings::ClockOn)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading clock... ");
		if (!clock.Load())
			CError::LogError(WARNING_CODE,"Failed to load the clock - ignoring.");
	}

	if (UserAbortedLoad())
	{
		return false;
	}
	SetSplashText("Done.");

	srand((unsigned int)timeGetTime());
	InitLight();
	camera.Init(&mainbody,(planetinfo?&info:NULL),CWindow::GetWidth(),CWindow::GetHeight());
	return FadeOutSplash();
}

void CGamePlay::DestroyScene()
{
	starmap.Free();
	lensflare.Free();
	flares=false;
	if (CSettings::ClockOn)
		clock.Free();
	mainbody.Destroy();
	info.Free();
	planetinfo=false;
}

void CGamePlay::UpdateScene()
{
	float seconds;
	static DWORD starttime=timeGetTime();
	int milidelta;
	milidelta=(timeGetTime()-starttime);
	seconds=milidelta*0.001f;
	mainbody.Update(seconds);
	camera.Update(seconds);
	if (flares)
		lensflare.UpdateTime(seconds);
	if (planetinfo)
		info.Update(seconds);
	if (CSettings::ClockOn==TRUE && milidelta>=500)
		clock.Update();
	if (RESTART_ALLOWED)
	{
		if (seconds>=max(RESTART_TIME,CAMERA_INIT_FADE_TIME))
		{
			mainbody.Restart();
			camera.Restart(seconds);
			if (flares)
				lensflare.Restart();
			if (planetinfo)
				info.Restart();
			starttime=starttime+milidelta;
		}
	}
}

void CGamePlay::DrawScene()
{
	GLfloat LightPosition[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	camera.ApplyRotation();
	starmap.Draw();
	camera.ApplyTranslation();
	glLightfv(GL_LIGHT1,GL_POSITION,LightPosition);
	mainbody.Draw(flares?&lensflare:NULL);
	if (flares)
	{
		lensflare.Draw();
	}
	if (planetinfo || CSettings::ClockOn)
	{
		Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
		if (planetinfo)
			info.Draw();
		if (CSettings::ClockOn)
			clock.Draw();
		Restore3D();
	}
	camera.DrawFade();
}

void CGamePlay::Frame()
{
	UpdateScene();
	SwapBuffers(wglGetCurrentDC());
	DrawScene();
	glFlush();
}

void CGamePlay::Prepare2D(int width, int height)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0,width,0,height);
	glMatrixMode(GL_MODELVIEW);
	glPushAttrib(GL_ENABLE_BIT);
}

void CGamePlay::Restore3D()
{
	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::UpdateSplash(const char *subtext)
{
	char text[256];
	strcpy(text,load_text);
	strcat(text,subtext);
	DrawSplash(text);
}

void CGamePlay::RenderSplashInner(const char *text)
{
	glLoadIdentity();
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_2D);
	if (splash_tex>0)
	{
		glColor4f(1,1,1,1);
		glBindTexture(GL_TEXTURE_2D,splash_tex);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0,0.25f);
			glVertex2f((float)splash_pos.x1,(float)splash_pos.y1);
			glTexCoord2f(1,0.25f);
			glVertex2f((float)splash_pos.x2,(float)splash_pos.y1);
			glTexCoord2f(1,1);
			glVertex2f((float)splash_pos.x2,(float)splash_pos.y2);
			glTexCoord2f(0,1);
			glVertex2f((float)splash_pos.x1,(float)splash_pos.y2);
		}
		glEnd();
	}
	int w=CWindow::GetWidth();
	float th;
	splashtext.GetTextSize(text,NULL,&th);
	int text_under_height=(int)(th*(SPLASH_TEXT_SPACING_COEFF-1.0f));
	int band_height=(int)(th*(2.0*SPLASH_TEXT_SPACING_COEFF-1.0f));
	glDisable(GL_TEXTURE_2D);
	glColor4f(0,0,0,1);
	glBegin(GL_QUADS);
	{
		glVertex2f(0.0f,0.0f);
		glVertex2f((float)w,0.0f);
		glVertex2f((float)w,(float)band_height);
		glVertex2f(0.0f,(float)band_height);
	}
	glEnd();
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glTranslatef(0.0f,(float)text_under_height,0.0f);
	glColor4f(SPLASH_TEXT_COLOR_R,SPLASH_TEXT_COLOR_G,SPLASH_TEXT_COLOR_B,1.0f);
	splashtext.Print(text);
}

void CGamePlay::DrawSplash(const char *text)
{
	Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
	glPushAttrib(GL_POLYGON_BIT);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	RenderSplashInner(text);
	glPopAttrib();
	Restore3D();
	glFlush();
	SwapBuffers(wglGetCurrentDC());
}

void CGamePlay::SetSplashText(const char *text)
{
	strcpy(load_text,text);
	DrawSplash(text);
}

bool CGamePlay::FadeOutSplash()
{
	int w=CWindow::GetWidth();
	int h=CWindow::GetHeight();
	int starttime=timeGetTime();
	float seconds;
	do
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		seconds=(float)(timeGetTime()-starttime)*0.001f;
		float alpha=min(seconds/CAMERA_INIT_FADE_TIME,1.0f);
		{
			Prepare2D(w,h);
			glPushAttrib(GL_POLYGON_BIT);
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
			RenderSplashInner(load_text);
			glLoadIdentity();
			glDisable(GL_DEPTH_TEST);
			glDisable(GL_TEXTURE_2D);
			glEnable(GL_BLEND);
			glColor4f(0,0,0,alpha);
			glBegin(GL_QUADS);
			{
				glVertex2f(0,0);
				glVertex2f((float)w,0);
				glVertex2f((float)w,(float)h);
				glVertex2f(0,(float)h);
			}
			glEnd();
			glPopAttrib();
			Restore3D();
			glFlush();
			SwapBuffers(wglGetCurrentDC());
		}
	}
	while (seconds<CAMERA_INIT_FADE_TIME);
	return true;
}
<commit_msg>Refactoring for readability.<commit_after>#include <windows.h>

#include <gl\gl.h>

#include "Settings.h"
#include "Main.h"
#include "VideoBase.h"
#include "Loader.h"
#include "Window.h"
#include "Text.h"
#include "Info.h"
#include "Error.h"
#include "GamePlay.h"

#define SPLASH_RESOURCE NULL
#define SPLASH_FILE "SPLASH.JPG"

#define SPLASH_FONT_NAME "Arial"
#define SPLASH_FONT_SIZE_AT_H600 12
#define SPLASH_FONT_SIZE (SPLASH_FONT_SIZE_AT_H600*CWindow::GetHeight()/600)
#define SPLASH_TEXT_SPACING_COEFF 1.75f

#define SPLASH_TEXT_COLOR_R 0.75f
#define SPLASH_TEXT_COLOR_G 0.75f
#define SPLASH_TEXT_COLOR_B 0.75f

#define RESTART_ALLOWED true
#define RESTART_TIME 10.0f

int CGamePlay::splash_tex=0;
char CGamePlay::load_text[256];
CGamePlay::splash_rect CGamePlay::splash_pos;
CBody CGamePlay::mainbody;
CCamera CGamePlay::camera;
CStarMap CGamePlay::starmap;
CClock CGamePlay::clock;
CLensFlare CGamePlay::lensflare;
bool CGamePlay::flares=false;
bool CGamePlay::planetinfo=false;
CText CGamePlay::splashtext;
CInfo CGamePlay::info;

CGamePlay::CGamePlay()
{
}

CGamePlay::~CGamePlay()
{
}

bool CGamePlay::Init()
{
	bool ret=true;
	if (!splashtext.BuildFTFont(SPLASH_FONT_NAME,SPLASH_FONT_SIZE))
		CError::LogError(WARNING_CODE,"Failed to load the splash text font - ignoring.");
	if (!InitScene())
	{
		if (UserAbortedLoad())
			OnUserAbortLoad();
		else
			CError::LogError(ERROR_CODE,"Unable to load scene critical data - aborting.");
		DestroyScene();
		ret=false;
	}
	FreeSplash();
	splashtext.Free();
	return ret;
}

void CGamePlay::ShutDown()
{
	DestroyScene();
}

void CGamePlay::CalcSplashRect()
{
	int w=CWindow::GetWidth();
	int h=CWindow::GetHeight();
	if (w*3>=h*4)
	{
		splash_pos.x1=(w-h*4/3)/2;
		splash_pos.x2=(w+h*4/3)/2;
		splash_pos.y1=0;
		splash_pos.y2=h;
	}
	else
	{
		splash_pos.x1=0;
		splash_pos.x2=w;
		splash_pos.y1=(h-w*3/4)/2;
		splash_pos.y2=(h+w*3/4)/2;
	}
}

bool CGamePlay::LoadSplash()
{
	CalcSplashRect();
	CLoader loader;
	loader.WithResource(SPLASH_RESOURCE);
	splash_tex=loader.LoadTexture(SPLASH_FILE,NULL,CVideoBase::GetOptMipmaps(),CVideoBase::GetOptLinear());
	return (splash_tex>0);
}

void CGamePlay::FreeSplash()
{
	glDeleteTextures(1,(GLuint*)&splash_tex);
	splash_tex=0;
}

void CGamePlay::InitLight()
{
	GLfloat LightAmbient[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1,GL_AMBIENT,LightAmbient);
	glLightfv(GL_LIGHT1,GL_DIFFUSE,LightDiffuse);
	glLightfv(GL_LIGHT1,GL_SPECULAR,LightSpecular);
	glEnable(GL_LIGHT1);
}

void CGamePlay::OnUserAbortLoad()
{
	// log new error
	CError::LogError(ERROR_CODE,"User aborted load.");
	// get first error, and if it's "user abort", clear the log so it's not printed
	if (CError::ErrorsOccured())
	{
		int code;
		char string[ERROR_MAXLEN];
		CError::Rewind();
		CError::GetNextError(&code,string);
		strlwr(string);
		if (strstr(string,"user") && strstr(string,"abort"))
			CError::Clear();
	}
}

bool CGamePlay::UserAbortedLoad()
{
	static bool userabort=false;
	if (!userabort)
		userabort=!MessagePump();
	return userabort;
}

bool CGamePlay::InitScene()
{
	{
		SetSplashText("Loading splash screen... ");
		if (!LoadSplash())
			CError::LogError(WARNING_CODE,"Failed to load the splash screen - ignoring.");
	}

	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading bodies... ");
		if (!mainbody.Load())
		{
			CError::LogError(ERROR_CODE,"Failed to load the bodies - aborting.");
			return false;
		}
	}

	flares=CVideoBase::GetOptLensFlares();
	if (flares)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading lens flares... ");
		if (!lensflare.Load(&mainbody))
		{
			CError::LogError(WARNING_CODE,"Failed to load the lens flares - ignoring.");
			flares=false;
		}
	}

	planetinfo=(CSettings::PlanetInfo==TRUE);
	if (planetinfo)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading info text font... ");
		if (!info.Load())
		{
			CError::LogError(WARNING_CODE,"Failed to load the planet info - ignoring.");
			planetinfo=false;
		}
	}

	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading starmap... ");
		if (!starmap.Load())
			CError::LogError(WARNING_CODE,"Failed to load the starmap - ignoring.");
	}

	if (CSettings::ClockOn)
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		SetSplashText("Loading clock... ");
		if (!clock.Load())
			CError::LogError(WARNING_CODE,"Failed to load the clock - ignoring.");
	}

	if (UserAbortedLoad())
	{
		return false;
	}
	SetSplashText("Done.");

	srand((unsigned int)timeGetTime());
	InitLight();
	camera.Init(&mainbody,(planetinfo?&info:NULL),CWindow::GetWidth(),CWindow::GetHeight());
	return FadeOutSplash();
}

void CGamePlay::DestroyScene()
{
	starmap.Free();
	lensflare.Free();
	flares=false;
	if (CSettings::ClockOn)
		clock.Free();
	mainbody.Destroy();
	info.Free();
	planetinfo=false;
}

void CGamePlay::UpdateScene()
{
	float seconds;
	static DWORD starttime=timeGetTime();
	int milidelta;
	milidelta=(timeGetTime()-starttime);
	seconds=milidelta*0.001f;
	mainbody.Update(seconds);
	camera.Update(seconds);
	if (flares)
		lensflare.UpdateTime(seconds);
	if (planetinfo)
		info.Update(seconds);
	if (CSettings::ClockOn==TRUE && milidelta>=500)
		clock.Update();
	if (RESTART_ALLOWED)
	{
		if (seconds>=max(RESTART_TIME,CAMERA_INIT_FADE_TIME))
		{
			mainbody.Restart();
			camera.Restart(seconds);
			if (flares)
				lensflare.Restart();
			if (planetinfo)
				info.Restart();
			starttime=starttime+milidelta;
		}
	}
}

void CGamePlay::DrawScene()
{
	GLfloat LightPosition[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	camera.ApplyRotation();
	starmap.Draw();
	camera.ApplyTranslation();
	glLightfv(GL_LIGHT1,GL_POSITION,LightPosition);
	mainbody.Draw(flares?&lensflare:NULL);
	if (flares)
	{
		lensflare.Draw();
	}
	if (planetinfo || CSettings::ClockOn)
	{
		Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
		if (planetinfo)
			info.Draw();
		if (CSettings::ClockOn)
			clock.Draw();
		Restore3D();
	}
	camera.DrawFade();
}

void CGamePlay::Frame()
{
	UpdateScene();
	SwapBuffers(wglGetCurrentDC());
	DrawScene();
	glFlush();
}

void CGamePlay::Prepare2D(int width, int height)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0,width,0,height);
	glMatrixMode(GL_MODELVIEW);
	glPushAttrib(GL_ENABLE_BIT);
}

void CGamePlay::Restore3D()
{
	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::UpdateSplash(const char *subtext)
{
	char text[256];
	strcpy(text,load_text);
	strcat(text,subtext);
	DrawSplash(text);
}

void CGamePlay::RenderSplashInner(const char *text)
{
	glLoadIdentity();
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_2D);
	if (splash_tex>0)
	{
		glColor4f(1,1,1,1);
		glBindTexture(GL_TEXTURE_2D,splash_tex);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0,0.25f);
			glVertex2f((float)splash_pos.x1,(float)splash_pos.y1);
			glTexCoord2f(1,0.25f);
			glVertex2f((float)splash_pos.x2,(float)splash_pos.y1);
			glTexCoord2f(1,1);
			glVertex2f((float)splash_pos.x2,(float)splash_pos.y2);
			glTexCoord2f(0,1);
			glVertex2f((float)splash_pos.x1,(float)splash_pos.y2);
		}
		glEnd();
	}
	int w=CWindow::GetWidth();
	float th;
	splashtext.GetTextSize(text,NULL,&th);
	int text_under_height=(int)(th*(SPLASH_TEXT_SPACING_COEFF-1.0f));
	int band_height=(int)(th*(2.0*SPLASH_TEXT_SPACING_COEFF-1.0f));
	glDisable(GL_TEXTURE_2D);
	glColor4f(0,0,0,1);
	glBegin(GL_QUADS);
	{
		glVertex2f(0.0f,0.0f);
		glVertex2f((float)w,0.0f);
		glVertex2f((float)w,(float)band_height);
		glVertex2f(0.0f,(float)band_height);
	}
	glEnd();
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glTranslatef(0.0f,(float)text_under_height,0.0f);
	glColor4f(SPLASH_TEXT_COLOR_R,SPLASH_TEXT_COLOR_G,SPLASH_TEXT_COLOR_B,1.0f);
	splashtext.Print(text);
}

void CGamePlay::DrawSplash(const char *text)
{
	Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
	glPushAttrib(GL_POLYGON_BIT);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	RenderSplashInner(text);
	glPopAttrib();
	Restore3D();
	glFlush();
	SwapBuffers(wglGetCurrentDC());
}

void CGamePlay::SetSplashText(const char *text)
{
	strcpy(load_text,text);
	DrawSplash(text);
}

bool CGamePlay::FadeOutSplash()
{
	int w=CWindow::GetWidth();
	int h=CWindow::GetHeight();
	int starttime=timeGetTime();
	float seconds;
	do
	{
		if (UserAbortedLoad())
		{
			return false;
		}
		seconds=(float)(timeGetTime()-starttime)*0.001f;
		float alpha=min(seconds/CAMERA_INIT_FADE_TIME,1.0f);
		{
			Prepare2D(w,h);
			glPushAttrib(GL_POLYGON_BIT);
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
			RenderSplashInner(load_text);
			glLoadIdentity();
			glDisable(GL_DEPTH_TEST);
			glDisable(GL_TEXTURE_2D);
			glEnable(GL_BLEND);
			glColor4f(0,0,0,alpha);
			glBegin(GL_QUADS);
			{
				glVertex2f(0,0);
				glVertex2f((float)w,0);
				glVertex2f((float)w,(float)h);
				glVertex2f(0,(float)h);
			}
			glEnd();
			glPopAttrib();
			Restore3D();
			glFlush();
			SwapBuffers(wglGetCurrentDC());
		}
	}
	while (seconds<CAMERA_INIT_FADE_TIME);
	return true;
}
<|endoftext|>


<commit_before><commit_msg>Correct out-of-order transform instances (#2025)<commit_after><|endoftext|>


<commit_before>/**
 * @file llnotificationsconsole.cpp
 * @brief Debugging console for unified notifications.
 *
 * $LicenseInfo:firstyear=2003&license=viewergpl$
 *
 * Copyright (c) 2003-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"
#include "llfloaternotificationsconsole.h"
#include "llnotifications.h"
#include "lluictrlfactory.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llpanel.h"
#include "llcombobox.h"

const S32 NOTIFICATION_PANEL_HEADER_HEIGHT = 20;
const S32 HEADER_PADDING = 38;

class LLNotificationChannelPanel : public LLPanel
{
public:
	LLNotificationChannelPanel(const std::string& channel_name);
	BOOL postBuild();

private:
	bool update(const LLSD& payload, bool passed_filter);
	static void toggleClick(void* user_data);
	static void onClickNotification(void* user_data);
	static void onClickNotificationReject(void* user_data);
	LLNotificationChannelPtr mChannelPtr;
	LLNotificationChannelPtr mChannelRejectsPtr;
};

LLNotificationChannelPanel::LLNotificationChannelPanel(const std::string& channel_name)
	: LLPanel()
{
	mChannelPtr = LLNotifications::instance().getChannel(channel_name);
	mChannelRejectsPtr = LLNotificationChannelPtr(
		LLNotificationChannel::buildChannel(channel_name + "rejects", mChannelPtr->getParentChannelName(),
											!boost::bind(mChannelPtr->getFilter(), _1)));
	LLUICtrlFactory::instance().buildPanel(this, "panel_notifications_channel.xml");
}

BOOL LLNotificationChannelPanel::postBuild()
{
	LLButton* header_button = getChild<LLButton>("header");
	header_button->setLabel(mChannelPtr->getName());
	header_button->setClickedCallback(toggleClick, this);

	mChannelPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, true));
	mChannelRejectsPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, false));

	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("notifications_list");
	scroll->setDoubleClickCallback(onClickNotification, this);
	scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0));
	scroll = getChild<LLScrollListCtrl>("notification_rejects_list");
	scroll->setDoubleClickCallback(onClickNotificationReject, this);
	scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0));
	return TRUE;
}

//static
void LLNotificationChannelPanel::toggleClick(void *user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;

	LLButton* header_button = self->getChild<LLButton>("header");

	LLLayoutStack* stack = dynamic_cast<LLLayoutStack*>(self->getParent());
	if (stack)
	{
		stack->collapsePanel(self, header_button->getToggleState());
	}

	// turn off tab stop for collapsed panel
	self->getChild<LLScrollListCtrl>("notifications_list")->setTabStop(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notifications_list")->setVisible(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notification_rejects_list")->setTabStop(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notification_rejects_list")->setVisible(!header_button->getToggleState());
}

/*static*/
void LLNotificationChannelPanel::onClickNotification(void* user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;
	LLScrollListItem* firstselected = self->getChild<LLScrollListCtrl>("notifications_list")->getFirstSelected();
	llassert(firstselected);
	if (firstselected)
	{
		void* data = firstselected->getUserdata();
		if (data)
		{
			gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE);
		}
	}
}

/*static*/
void LLNotificationChannelPanel::onClickNotificationReject(void* user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;
	LLScrollListItem* firstselected = self->getChild<LLScrollListCtrl>("notification_rejects_list")->getFirstSelected();
	llassert(firstselected);
	if (firstselected)
	{
		void* data = firstselected->getUserdata();
		if (data)
		{
			gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE);
		}
	}
}

bool LLNotificationChannelPanel::update(const LLSD& payload, bool passed_filter)
{
	LLNotificationPtr notification = LLNotifications::instance().find(payload["id"].asUUID());
	if (notification)
	{
		LLSD row;
		row["columns"][0]["value"] = notification->getName();
		row["columns"][0]["column"] = "name";

		row["columns"][1]["value"] = notification->getMessage();
		row["columns"][1]["column"] = "content";

		row["columns"][2]["value"] = notification->getDate();
		row["columns"][2]["column"] = "date";
		row["columns"][2]["type"] = "date";

		LLScrollListItem* sli = passed_filter ?
			getChild<LLScrollListCtrl>("notifications_list")->addElement(row) :
			getChild<LLScrollListCtrl>("notification_rejects_list")->addElement(row);
		sli->setUserdata(&(*notification));
	}

	return false;
}

//
// LLFloaterNotificationConsole
//
LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key)
: LLFloater(key)
{
	mCommitCallbackRegistrar.add("ClickAdd",     boost::bind(&LLFloaterNotificationConsole::onClickAdd, this));

	//LLUICtrlFactory::instance().buildFloater(this, "floater_notifications_console.xml");
}

BOOL LLFloaterNotificationConsole::postBuild()
{
	// these are in the order of processing
	addChannel("Unexpired");
	addChannel("Ignore");
	addChannel("Visible", true);
	// all the ones below attach to the Visible channel
	addChannel("History");
	addChannel("Alerts");
	addChannel("AlertModal");
	addChannel("Group Notifications");
	addChannel("Notifications");
	addChannel("NotificationTips");

//	getChild<LLButton>("add_notification")->setClickedCallback(onClickAdd, this);

	LLComboBox* notifications = getChild<LLComboBox>("notification_types");
	LLNotifications::TemplateNames names = LLNotifications::instance().getTemplateNames();
	for (LLNotifications::TemplateNames::iterator template_it = names.begin();
		template_it != names.end();
		++template_it)
	{
		notifications->add(*template_it);
	}
	notifications->sortByName();

	return TRUE;
}

void LLFloaterNotificationConsole::addChannel(const std::string& name, bool open)
{
	LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels");
	LLNotificationChannelPanel* panelp = new LLNotificationChannelPanel(name);
	stack.addPanel(panelp, 0, NOTIFICATION_PANEL_HEADER_HEIGHT, S32_MAX, S32_MAX, TRUE, TRUE, LLLayoutStack::ANIMATE);

	LLButton& header_button = panelp->getChildRef<LLButton>("header");
	header_button.setToggleState(!open);
	stack.collapsePanel(panelp, !open);

	updateResizeLimits();
}

void LLFloaterNotificationConsole::removeChannel(const std::string& name)
{
	LLPanel* panelp = getChild<LLPanel>(name);
	getChildRef<LLLayoutStack>("notification_channels").removePanel(panelp);
	delete panelp;

	updateResizeLimits();
}

//static
void LLFloaterNotificationConsole::updateResizeLimits()
{
	const LLFloater::Params& floater_params = LLFloater::getDefaultParams();
	S32 floater_header_size = floater_params.header_height;

	LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels");
	setResizeLimits(getMinWidth(), floater_header_size + HEADER_PADDING + ((NOTIFICATION_PANEL_HEADER_HEIGHT + 3) * stack.getNumPanels()));
}

void LLFloaterNotificationConsole::onClickAdd()
{
	std::string message_name = getChild<LLComboBox>("notification_types")->getValue().asString();
	if (!message_name.empty())
	{
		LLNotifications::instance().add(message_name, LLSD(), LLSD());
	}
}

//=============== LLFloaterNotification ================

LLFloaterNotification::LLFloaterNotification(LLNotification* note)
:	LLFloater(LLSD()),
	mNote(note)
{
	LLUICtrlFactory::instance().buildFloater(this, "floater_notification.xml", NULL);
}

BOOL LLFloaterNotification::postBuild()
{
	setTitle(mNote->getName());
	getChild<LLUICtrl>("payload")->setValue(mNote->getMessage());

	LLComboBox* responses_combo = getChild<LLComboBox>("response");
	LLCtrlListInterface* response_list = responses_combo->getListInterface();
	LLNotificationFormPtr form(mNote->getForm());
	if(!form)
	{
		return TRUE;
	}

	responses_combo->setCommitCallback(onCommitResponse, this);

	LLSD form_sd = form->asLLSD();

	for (LLSD::array_const_iterator form_item = form_sd.beginArray(); form_item != form_sd.endArray(); ++form_item)
	{
		if ( (*form_item)["type"].asString() != "button") continue;
		std::string text = (*form_item)["text"].asString();
		response_list->addSimpleElement(text);
	}

	return TRUE;
}

void LLFloaterNotification::respond()
{
	LLComboBox* responses_combo = getChild<LLComboBox>("response");
	LLCtrlListInterface* response_list = responses_combo->getListInterface();
	const std::string& trigger = response_list->getSelectedValue().asString();
	//llinfos << trigger << llendl;

	LLSD response = mNote->getResponseTemplate();
	response[trigger] = true;
	mNote->respond(response);
}
<commit_msg>EXT-7460 FIXED (VWR-19451) Viewer crashes when opening notifications console.<commit_after>/**
 * @file llnotificationsconsole.cpp
 * @brief Debugging console for unified notifications.
 *
 * $LicenseInfo:firstyear=2003&license=viewergpl$
 *
 * Copyright (c) 2003-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"
#include "llfloaternotificationsconsole.h"
#include "llnotifications.h"
#include "lluictrlfactory.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llpanel.h"
#include "llcombobox.h"

const S32 NOTIFICATION_PANEL_HEADER_HEIGHT = 20;
const S32 HEADER_PADDING = 38;

class LLNotificationChannelPanel : public LLPanel
{
public:
	LLNotificationChannelPanel(const std::string& channel_name);
	BOOL postBuild();

private:
	bool update(const LLSD& payload, bool passed_filter);
	static void toggleClick(void* user_data);
	static void onClickNotification(void* user_data);
	static void onClickNotificationReject(void* user_data);
	LLNotificationChannelPtr mChannelPtr;
	LLNotificationChannelPtr mChannelRejectsPtr;
};

LLNotificationChannelPanel::LLNotificationChannelPanel(const std::string& channel_name)
	: LLPanel()
{
	mChannelPtr = LLNotifications::instance().getChannel(channel_name);
	mChannelRejectsPtr = LLNotificationChannelPtr(
		LLNotificationChannel::buildChannel(channel_name + "rejects", mChannelPtr->getParentChannelName(),
											!boost::bind(mChannelPtr->getFilter(), _1)));
	LLUICtrlFactory::instance().buildPanel(this, "panel_notifications_channel.xml");
}

BOOL LLNotificationChannelPanel::postBuild()
{
	LLButton* header_button = getChild<LLButton>("header");
	header_button->setLabel(mChannelPtr->getName());
	header_button->setClickedCallback(toggleClick, this);

	mChannelPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, true));
	mChannelRejectsPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, false));

	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("notifications_list");
	scroll->setDoubleClickCallback(onClickNotification, this);
	scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0));
	scroll = getChild<LLScrollListCtrl>("notification_rejects_list");
	scroll->setDoubleClickCallback(onClickNotificationReject, this);
	scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0));
	return TRUE;
}

//static
void LLNotificationChannelPanel::toggleClick(void *user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;

	LLButton* header_button = self->getChild<LLButton>("header");

	LLLayoutStack* stack = dynamic_cast<LLLayoutStack*>(self->getParent());
	if (stack)
	{
		stack->collapsePanel(self, header_button->getToggleState());
	}

	// turn off tab stop for collapsed panel
	self->getChild<LLScrollListCtrl>("notifications_list")->setTabStop(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notifications_list")->setVisible(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notification_rejects_list")->setTabStop(!header_button->getToggleState());
	self->getChild<LLScrollListCtrl>("notification_rejects_list")->setVisible(!header_button->getToggleState());
}

/*static*/
void LLNotificationChannelPanel::onClickNotification(void* user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;
	LLScrollListItem* firstselected = self->getChild<LLScrollListCtrl>("notifications_list")->getFirstSelected();
	llassert(firstselected);
	if (firstselected)
	{
		void* data = firstselected->getUserdata();
		if (data)
		{
			gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE);
		}
	}
}

/*static*/
void LLNotificationChannelPanel::onClickNotificationReject(void* user_data)
{
	LLNotificationChannelPanel* self = (LLNotificationChannelPanel*)user_data;
	if (!self) return;
	LLScrollListItem* firstselected = self->getChild<LLScrollListCtrl>("notification_rejects_list")->getFirstSelected();
	llassert(firstselected);
	if (firstselected)
	{
		void* data = firstselected->getUserdata();
		if (data)
		{
			gFloaterView->getParentFloater(self)->addDependentFloater(new LLFloaterNotification((LLNotification*)data), TRUE);
		}
	}
}

bool LLNotificationChannelPanel::update(const LLSD& payload, bool passed_filter)
{
	LLNotificationPtr notification = LLNotifications::instance().find(payload["id"].asUUID());
	if (notification)
	{
		LLSD row;
		row["columns"][0]["value"] = notification->getName();
		row["columns"][0]["column"] = "name";

		row["columns"][1]["value"] = notification->getMessage();
		row["columns"][1]["column"] = "content";

		row["columns"][2]["value"] = notification->getDate();
		row["columns"][2]["column"] = "date";
		row["columns"][2]["type"] = "date";

		LLScrollListItem* sli = passed_filter ?
			getChild<LLScrollListCtrl>("notifications_list")->addElement(row) :
			getChild<LLScrollListCtrl>("notification_rejects_list")->addElement(row);
		sli->setUserdata(&(*notification));
	}

	return false;
}

//
// LLFloaterNotificationConsole
//
LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key)
: LLFloater(key)
{
	mCommitCallbackRegistrar.add("ClickAdd",     boost::bind(&LLFloaterNotificationConsole::onClickAdd, this));

	//LLUICtrlFactory::instance().buildFloater(this, "floater_notifications_console.xml");
}

BOOL LLFloaterNotificationConsole::postBuild()
{
	// these are in the order of processing
	addChannel("Unexpired");
	addChannel("Ignore");
	addChannel("Visible", true);
	// all the ones below attach to the Visible channel
	addChannel("Persistent");
	addChannel("Alerts");
	addChannel("AlertModal");
	addChannel("Group Notifications");
	addChannel("Notifications");
	addChannel("NotificationTips");

//	getChild<LLButton>("add_notification")->setClickedCallback(onClickAdd, this);

	LLComboBox* notifications = getChild<LLComboBox>("notification_types");
	LLNotifications::TemplateNames names = LLNotifications::instance().getTemplateNames();
	for (LLNotifications::TemplateNames::iterator template_it = names.begin();
		template_it != names.end();
		++template_it)
	{
		notifications->add(*template_it);
	}
	notifications->sortByName();

	return TRUE;
}

void LLFloaterNotificationConsole::addChannel(const std::string& name, bool open)
{
	LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels");
	LLNotificationChannelPanel* panelp = new LLNotificationChannelPanel(name);
	stack.addPanel(panelp, 0, NOTIFICATION_PANEL_HEADER_HEIGHT, S32_MAX, S32_MAX, TRUE, TRUE, LLLayoutStack::ANIMATE);

	LLButton& header_button = panelp->getChildRef<LLButton>("header");
	header_button.setToggleState(!open);
	stack.collapsePanel(panelp, !open);

	updateResizeLimits();
}

void LLFloaterNotificationConsole::removeChannel(const std::string& name)
{
	LLPanel* panelp = getChild<LLPanel>(name);
	getChildRef<LLLayoutStack>("notification_channels").removePanel(panelp);
	delete panelp;

	updateResizeLimits();
}

//static
void LLFloaterNotificationConsole::updateResizeLimits()
{
	const LLFloater::Params& floater_params = LLFloater::getDefaultParams();
	S32 floater_header_size = floater_params.header_height;

	LLLayoutStack& stack = getChildRef<LLLayoutStack>("notification_channels");
	setResizeLimits(getMinWidth(), floater_header_size + HEADER_PADDING + ((NOTIFICATION_PANEL_HEADER_HEIGHT + 3) * stack.getNumPanels()));
}

void LLFloaterNotificationConsole::onClickAdd()
{
	std::string message_name = getChild<LLComboBox>("notification_types")->getValue().asString();
	if (!message_name.empty())
	{
		LLNotifications::instance().add(message_name, LLSD(), LLSD());
	}
}

//=============== LLFloaterNotification ================

LLFloaterNotification::LLFloaterNotification(LLNotification* note)
:	LLFloater(LLSD()),
	mNote(note)
{
	LLUICtrlFactory::instance().buildFloater(this, "floater_notification.xml", NULL);
}

BOOL LLFloaterNotification::postBuild()
{
	setTitle(mNote->getName());
	getChild<LLUICtrl>("payload")->setValue(mNote->getMessage());

	LLComboBox* responses_combo = getChild<LLComboBox>("response");
	LLCtrlListInterface* response_list = responses_combo->getListInterface();
	LLNotificationFormPtr form(mNote->getForm());
	if(!form)
	{
		return TRUE;
	}

	responses_combo->setCommitCallback(onCommitResponse, this);

	LLSD form_sd = form->asLLSD();

	for (LLSD::array_const_iterator form_item = form_sd.beginArray(); form_item != form_sd.endArray(); ++form_item)
	{
		if ( (*form_item)["type"].asString() != "button") continue;
		std::string text = (*form_item)["text"].asString();
		response_list->addSimpleElement(text);
	}

	return TRUE;
}

void LLFloaterNotification::respond()
{
	LLComboBox* responses_combo = getChild<LLComboBox>("response");
	LLCtrlListInterface* response_list = responses_combo->getListInterface();
	const std::string& trigger = response_list->getSelectedValue().asString();
	//llinfos << trigger << llendl;

	LLSD response = mNote->getResponseTemplate();
	response[trigger] = true;
	mNote->respond(response);
}
<|endoftext|>


<commit_before> /*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: accpreview.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 08:23:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif
#ifndef _ACCESS_HRC
#include "access.hrc"
#endif
#ifndef _ACCPREVIEW_HXX
#include <accpreview.hxx>
#endif

const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextDocumentPageView";
const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleDocumentPageView";

// using namespace accessibility;

using ::com::sun::star::lang::IndexOutOfBoundsException;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::uno::Sequence;
using ::rtl::OUString;

//
// SwAccessiblePreview
//

SwAccessiblePreview::SwAccessiblePreview( SwAccessibleMap *pMp ) :
    SwAccessibleDocumentBase( pMp )
{
    SetName( GetResource( STR_ACCESS_DOC_NAME ) );
}

SwAccessiblePreview::~SwAccessiblePreview()
{
}

OUString SwAccessiblePreview::getImplementationName( )
    throw( RuntimeException )
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( sImplementationName ) );
}

sal_Bool SwAccessiblePreview::supportsService( const OUString& rServiceName )
    throw( RuntimeException )
{
    return rServiceName.equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( sServiceName) ) ||
        rServiceName.equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( sAccessibleServiceName ) );
}

Sequence<OUString> SwAccessiblePreview::getSupportedServiceNames( )
    throw( RuntimeException )
{
    Sequence<OUString> aSeq( 2 );
    aSeq[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( sServiceName ) );
    aSeq[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( sAccessibleServiceName ) );
    return aSeq;
}

Sequence< sal_Int8 > SAL_CALL SwAccessiblePreview::getImplementationId()
        throw(RuntimeException)
{
    vos::OGuard aGuard(Application::GetSolarMutex());
    static Sequence< sal_Int8 > aId( 16 );
    static sal_Bool bInit = sal_False;
    if(!bInit)
    {
        rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
        bInit = sal_True;
    }
    return aId;
}
<commit_msg>INTEGRATION: CWS changefileheader (1.10.242); FILE MERGED 2008/04/01 15:56:43 thb 1.10.242.3: #i85898# Stripping all external header guards 2008/04/01 12:53:46 thb 1.10.242.2: #i85898# Stripping all external header guards 2008/03/31 16:53:39 rt 1.10.242.1: #i87441# Change license header to LPGL v3.<commit_after> /*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: accpreview.cxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <vcl/svapp.hxx>
#include <rtl/uuid.h>
#ifndef _ACCESS_HRC
#include "access.hrc"
#endif
#include <accpreview.hxx>

const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextDocumentPageView";
const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleDocumentPageView";

// using namespace accessibility;

using ::com::sun::star::lang::IndexOutOfBoundsException;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::uno::Sequence;
using ::rtl::OUString;

//
// SwAccessiblePreview
//

SwAccessiblePreview::SwAccessiblePreview( SwAccessibleMap *pMp ) :
    SwAccessibleDocumentBase( pMp )
{
    SetName( GetResource( STR_ACCESS_DOC_NAME ) );
}

SwAccessiblePreview::~SwAccessiblePreview()
{
}

OUString SwAccessiblePreview::getImplementationName( )
    throw( RuntimeException )
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( sImplementationName ) );
}

sal_Bool SwAccessiblePreview::supportsService( const OUString& rServiceName )
    throw( RuntimeException )
{
    return rServiceName.equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( sServiceName) ) ||
        rServiceName.equalsAsciiL(
                RTL_CONSTASCII_STRINGPARAM( sAccessibleServiceName ) );
}

Sequence<OUString> SwAccessiblePreview::getSupportedServiceNames( )
    throw( RuntimeException )
{
    Sequence<OUString> aSeq( 2 );
    aSeq[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( sServiceName ) );
    aSeq[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( sAccessibleServiceName ) );
    return aSeq;
}

Sequence< sal_Int8 > SAL_CALL SwAccessiblePreview::getImplementationId()
        throw(RuntimeException)
{
    vos::OGuard aGuard(Application::GetSolarMutex());
    static Sequence< sal_Int8 > aId( 16 );
    static sal_Bool bInit = sal_False;
    if(!bInit)
    {
        rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
        bInit = sal_True;
    }
    return aId;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include <kcpolydb.h>

long estimate_a(long *pack) {
  return (
    4 + pack[0] * 8 +
    4 + 1 + pack[1] * 8 * 5 +
    4 + 1 + pack[2] * 8 * 5 + 3 * 11 * 1 +
    4 + 1 + pack[3] * 8 * 5 + 3 * 11 * 2 +
    4 + 1 + pack[4] * 8 * 5 + 3 * 11 * 4 +
    4 + 1 + pack[5] * 8 * 5 + 3 * 11 * 6
  );
}

long estimate_b(long *pack) {
  return (
    4 + pack[0] * 9 +
    4 + 1 + pack[1] * 9 * 5 +
    4 + 1 + pack[2] * 9 * 5 + 4 * 2 * 3 * 8 * 1 +
    4 + 1 + pack[3] * 9 * 5 + 4 * 2 * 3 * 8 * 2 +
    4 + 1 + pack[4] * 9 * 5 + 4 * 2 * 3 * 8 * 4 +
    4 + 1 + pack[5] * 9 * 5 + 4 * 2 * 3 * 8 * 6
  );
}

int main(int argc, char **argv) {
    if (argc <= 1) {
      std::cout << "Usage: stat <dbfile.kct>" << std::endl;
      return 1;
    }

    kyotocabinet::TreeDB db;

    if (!db.open(argv[1], kyotocabinet::TreeDB::OREADER)) {
      std::cout << "Could not open database." << std::endl;
      return 2;
    }

    std::auto_ptr<kyotocabinet::TreeDB::Cursor> cur(db.cursor());
    cur->jump();

    std::string key, value;

    long pack[] = {0, 0, 0, 0, 0, 0};
    long total = 0;

    std::cout << "Scanning ..." << std::endl;

    while (cur->get(&key, &value, true)) {
        total++;
        if (value.size() == 8) {
            pack[0]++;
        } else {
            pack[value.at(0)]++;
        }

        if (total % 50000 == 0) {
            std::cerr << ".";
        }
    }

    std::cerr << std::endl;

    for (int i = 0; i < 5; i++) {
        std::cout << "Pack format " << i << ": " << pack[i] << " nodes " << std::endl;
    }

    std::cout << "Unique positions: " << total << std::endl;

    std::cout << std::endl;

    std::cout << "Scheme A: " << estimate_a(pack) << " bytes" << std::endl;
    std::cout << "Scheme B: " << estimate_b(pack) << " bytes" << std::endl;
    std::cout << "B/A: " << ((double)estimate_b(pack)/estimate_a(pack)) << std::endl;

    return 0;
}
<commit_msg>Do not require lock for stats<commit_after>#include <iostream>
#include <string>

#include <kcpolydb.h>

long estimate_a(long *pack) {
  return (
    4 + pack[0] * 8 +
    4 + 1 + pack[1] * 8 * 5 +
    4 + 1 + pack[2] * 8 * 5 + 3 * 11 * 1 +
    4 + 1 + pack[3] * 8 * 5 + 3 * 11 * 2 +
    4 + 1 + pack[4] * 8 * 5 + 3 * 11 * 4 +
    4 + 1 + pack[5] * 8 * 5 + 3 * 11 * 6
  );
}

long estimate_b(long *pack) {
  return (
    4 + pack[0] * 9 +
    4 + 1 + pack[1] * 9 * 5 +
    4 + 1 + pack[2] * 9 * 5 + 4 * 2 * 3 * 8 * 1 +
    4 + 1 + pack[3] * 9 * 5 + 4 * 2 * 3 * 8 * 2 +
    4 + 1 + pack[4] * 9 * 5 + 4 * 2 * 3 * 8 * 4 +
    4 + 1 + pack[5] * 9 * 5 + 4 * 2 * 3 * 8 * 6
  );
}

int main(int argc, char **argv) {
    if (argc <= 1) {
      std::cout << "Usage: stat <dbfile.kct>" << std::endl;
      return 1;
    }

    kyotocabinet::TreeDB db;

    if (!db.open(argv[1], kyotocabinet::TreeDB::OREADER | kyotocabinet::TreeDB::ONOLOCK)) {
      std::cout << "Could not open database." << std::endl;
      return 2;
    }

    std::auto_ptr<kyotocabinet::TreeDB::Cursor> cur(db.cursor());
    cur->jump();

    std::string key, value;

    long pack[] = {0, 0, 0, 0, 0, 0};
    long total = 0;

    std::cout << "Scanning ..." << std::endl;

    while (cur->get(&key, &value, true)) {
        total++;
        if (value.size() == 8) {
            pack[0]++;
        } else {
            pack[value.at(0)]++;
        }

        if (total % 50000 == 0) {
            std::cerr << ".";
        }
    }

    std::cerr << std::endl;

    for (int i = 0; i < 5; i++) {
        std::cout << "Pack format " << i << ": " << pack[i] << " nodes " << std::endl;
    }

    std::cout << "Unique positions: " << total << std::endl;

    std::cout << std::endl;

    std::cout << "Scheme A: " << estimate_a(pack) << " bytes" << std::endl;
    std::cout << "Scheme B: " << estimate_b(pack) << " bytes" << std::endl;
    std::cout << "B/A: " << ((double)estimate_b(pack)/estimate_a(pack)) << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/experimental/symbolizer/Symbolizer.h>

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits.h>
#include <unistd.h>

#ifdef __GNUC__
#include <ext/stdio_filebuf.h>
#include <ext/stdio_sync_filebuf.h>
#endif

#include <folly/Conv.h>
#include <folly/FileUtil.h>
#include <folly/ScopeGuard.h>
#include <folly/String.h>

#include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/Dwarf.h>
#include <folly/experimental/symbolizer/LineReader.h>

namespace folly {
namespace symbolizer {

namespace {

/**
 * Read a hex value.
 */
uintptr_t readHex(StringPiece& sp) {
  uintptr_t val = 0;
  const char* p = sp.begin();
  for (; p != sp.end(); ++p) {
    unsigned int v;
    if (*p >= '0' && *p <= '9') {
      v = (*p - '0');
    } else if (*p >= 'a' && *p <= 'f') {
      v = (*p - 'a') + 10;
    } else if (*p >= 'A' && *p <= 'F') {
      v = (*p - 'A') + 10;
    } else {
      break;
    }
    val = (val << 4) + v;
  }
  sp.assign(p, sp.end());
  return val;
}

/**
 * Skip over non-space characters.
 */
void skipNS(StringPiece& sp) {
  const char* p = sp.begin();
  for (; p != sp.end() && (*p != ' ' && *p != '\t'); ++p) { }
  sp.assign(p, sp.end());
}

/**
 * Skip over space and tab characters.
 */
void skipWS(StringPiece& sp) {
  const char* p = sp.begin();
  for (; p != sp.end() && (*p == ' ' || *p == '\t'); ++p) { }
  sp.assign(p, sp.end());
}

/**
 * Parse a line from /proc/self/maps
 */
bool parseProcMapsLine(StringPiece line,
                       uintptr_t& from,
                       uintptr_t& to,
                       uintptr_t& fileOff,
                       bool& isSelf,
                       StringPiece& fileName) {
  isSelf = false;
  // from     to       perm offset   dev   inode             path
  // 00400000-00405000 r-xp 00000000 08:03 35291182          /bin/cat
  if (line.empty()) {
    return false;
  }

  // Remove trailing newline, if any
  if (line.back() == '\n') {
    line.pop_back();
  }

  // from
  from = readHex(line);
  if (line.empty() || line.front() != '-') {
    return false;
  }
  line.pop_front();

  // to
  to = readHex(line);
  if (line.empty() || line.front() != ' ') {
    return false;
  }
  line.pop_front();

  // perms
  skipNS(line);
  if (line.empty() || line.front() != ' ') {
    return false;
  }
  line.pop_front();

  uintptr_t fileOffset = readHex(line);
  if (line.empty() || line.front() != ' ') {
    return false;
  }
  line.pop_front();
  // main mapping starts at 0 but there can be multi-segment binary
  // such as
  // from     to       perm offset   dev   inode             path
  // 00400000-00405000 r-xp 00000000 08:03 54011424          /bin/foo
  // 00600000-00605000 r-xp 00020000 08:03 54011424          /bin/foo
  // 00800000-00805000 r-xp 00040000 08:03 54011424          /bin/foo
  // if the offset > 0, this indicates to the caller that the baseAddress
  // need to be used for undo relocation step.
  fileOff = fileOffset;

  // dev
  skipNS(line);
  if (line.empty() || line.front() != ' ') {
    return false;
  }
  line.pop_front();

  // inode
  skipNS(line);
  if (line.empty() || line.front() != ' ') {
    return false;
  }

  // if inode is 0, such as in case of ANON pages, there should be atleast
  // one white space before EOL
  skipWS(line);
  if (line.empty()) {
    // There will be no fileName for ANON text pages
    // if the parsing came this far without a fileName, then from/to address
    // may contain text in ANON pages.
    isSelf = true;
    fileName.clear();
    return true;
  }

  fileName = line;
  return true;
}

ElfCache* defaultElfCache() {
  static constexpr size_t defaultCapacity = 500;
  static auto cache = new ElfCache(defaultCapacity);
  return cache;
}

}  // namespace

void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
                          uintptr_t address) {
  clear();
  found = true;

  address += file->getBaseAddress();
  auto sym = file->getDefinitionByAddress(address);
  if (!sym.first) {
    return;
  }

  file_ = file;
  name = file->getSymbolName(sym);

  Dwarf(file.get()).findAddress(address, location);
}

Symbolizer::Symbolizer(ElfCacheBase* cache)
  : cache_(cache ?: defaultElfCache()) {
}

void Symbolizer::symbolize(const uintptr_t* addresses,
                           SymbolizedFrame* frames,
                           size_t addressCount) {
  size_t remaining = 0;
  for (size_t i = 0; i < addressCount; ++i) {
    auto& frame = frames[i];
    if (!frame.found) {
      ++remaining;
      frame.clear();
    }
  }

  if (remaining == 0) {  // we're done
    return;
  }

  int fd = openNoInt("/proc/self/maps", O_RDONLY);
  if (fd == -1) {
    return;
  }

  char selfFile[PATH_MAX + 8];
  ssize_t selfSize;
  if ((selfSize = readlink("/proc/self/exe", selfFile, PATH_MAX + 1)) == -1) {
    // something terribly wrong
    return;
  }
  selfFile[selfSize] = '\0';

  char buf[PATH_MAX + 100];  // Long enough for any line
  LineReader reader(fd, buf, sizeof(buf));

  while (remaining != 0) {
    StringPiece line;
    if (reader.readLine(line) != LineReader::kReading) {
      break;
    }

    // Parse line
    uintptr_t from;
    uintptr_t to;
    uintptr_t fileOff;
    uintptr_t base;
    bool isSelf = false; // fileName can potentially be '/proc/self/exe'
    StringPiece fileName;
    if (!parseProcMapsLine(line, from, to, fileOff, isSelf, fileName)) {
      continue;
    }

    base = from;
    bool first = true;
    std::shared_ptr<ElfFile> elfFile;

    // case of text on ANON?
    // Recompute from/to/base from the executable
    if (isSelf && fileName.empty()) {
      elfFile = cache_->getFile(selfFile);

      if (elfFile != nullptr) {
        auto textSection = elfFile->getSectionByName(".text");
        base = elfFile->getBaseAddress();
        from = textSection->sh_addr;
        to = from + textSection->sh_size;
        fileName = selfFile;
        first = false; // no need to get this file again from the cache
      }
    }

    // See if any addresses are here
    for (size_t i = 0; i < addressCount; ++i) {
      auto& frame = frames[i];
      if (frame.found) {
        continue;
      }

      uintptr_t address = addresses[i];

      if (from > address || address >= to) {
        continue;
      }

      // Found
      frame.found = true;
      --remaining;

      // Open the file on first use
      if (first) {
        first = false;
        elfFile = cache_->getFile(fileName);

        // Need to get the correct base address as from
        // when fileOff > 0
        if (fileOff && elfFile != nullptr) {
          base = elfFile->getBaseAddress();
        }
      }

      if (!elfFile) {
        continue;
      }

      // Undo relocation
      frame.set(elfFile, address - base);
    }
  }

  closeNoInt(fd);
}

namespace {
constexpr char kHexChars[] = "0123456789abcdef";
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
}  // namespace

constexpr char AddressFormatter::bufTemplate[];
constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
    SymbolizePrinter::kColorMap;

AddressFormatter::AddressFormatter() {
  memcpy(buf_, bufTemplate, sizeof(buf_));
}

folly::StringPiece AddressFormatter::format(uintptr_t address) {
  // Can't use sprintf, not async-signal-safe
  static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
  char* end = buf_ + sizeof(buf_) - 1 - (16 - 2 * sizeof(uintptr_t));
  char* p = end;
  *p-- = '\0';
  while (address != 0) {
    *p-- = kHexChars[address & 0xf];
    address >>= 4;
  }

  return folly::StringPiece(buf_, end);
}

void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
  if (options_ & TERSE) {
    printTerse(address, frame);
    return;
  }

  SCOPE_EXIT { color(Color::DEFAULT); };

  if (!(options_ & NO_FRAME_ADDRESS)) {
    color(kAddressColor);

    AddressFormatter formatter;
    doPrint(formatter.format(address));
  }

  const char padBuf[] = "                       ";
  folly::StringPiece pad(padBuf,
                         sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));

  color(kFunctionColor);
  if (!frame.found) {
    doPrint(" (not found)");
    return;
  }

  if (!frame.name || frame.name[0] == '\0') {
    doPrint(" (unknown)");
  } else {
    char demangledBuf[2048];
    demangle(frame.name, demangledBuf, sizeof(demangledBuf));
    doPrint(" ");
    doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  }

  if (!(options_ & NO_FILE_AND_LINE)) {
    color(kFileColor);
    char fileBuf[PATH_MAX];
    fileBuf[0] = '\0';
    if (frame.location.hasFileAndLine) {
      frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
      doPrint("\n");
      doPrint(pad);
      doPrint(fileBuf);

      char buf[22];
      uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
      doPrint(":");
      doPrint(StringPiece(buf, n));
    }

    if (frame.location.hasMainFile) {
      char mainFileBuf[PATH_MAX];
      mainFileBuf[0] = '\0';
      frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf));
      if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) {
        doPrint("\n");
        doPrint(pad);
        doPrint("-> ");
        doPrint(mainFileBuf);
      }
    }
  }
}

void SymbolizePrinter::color(SymbolizePrinter::Color color) {
  if ((options_ & COLOR) == 0 &&
      ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
    return;
  }
  if (color < 0 || color >= kColorMap.size()) {
    return;
  }
  doPrint(kColorMap[color]);
}

void SymbolizePrinter::println(uintptr_t address,
                               const SymbolizedFrame& frame) {
  print(address, frame);
  doPrint("\n");
}

void SymbolizePrinter::printTerse(uintptr_t address,
                                  const SymbolizedFrame& frame) {
  if (frame.found && frame.name && frame.name[0] != '\0') {
    char demangledBuf[2048] = {0};
    demangle(frame.name, demangledBuf, sizeof(demangledBuf));
    doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  } else {
    // Can't use sprintf, not async-signal-safe
    static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
    char buf[] = "0x0000000000000000";
    char* end = buf + sizeof(buf) - 1 - (16 - 2 * sizeof(uintptr_t));
    char* p = end;
    *p-- = '\0';
    while (address != 0) {
      *p-- = kHexChars[address & 0xf];
      address >>= 4;
    }
    doPrint(StringPiece(buf, end));
  }
}

void SymbolizePrinter::println(const uintptr_t* addresses,
                               const SymbolizedFrame* frames,
                               size_t frameCount) {
  for (size_t i = 0; i < frameCount; ++i) {
    println(addresses[i], frames[i]);
  }
}

namespace {

int getFD(const std::ios& stream) {
#ifdef __GNUC__
  std::streambuf* buf = stream.rdbuf();
  using namespace __gnu_cxx;

  {
    auto sbuf = dynamic_cast<stdio_sync_filebuf<char>*>(buf);
    if (sbuf) {
      return fileno(sbuf->file());
    }
  }
  {
    auto sbuf = dynamic_cast<stdio_filebuf<char>*>(buf);
    if (sbuf) {
      return sbuf->fd();
    }
  }
#endif  // __GNUC__
  return -1;
}

bool isColorfulTty(int options, int fd) {
  if ((options & SymbolizePrinter::TERSE) != 0 ||
      (options & SymbolizePrinter::COLOR_IF_TTY) == 0 ||
      fd < 0 || !::isatty(fd)) {
    return false;
  }
  auto term = ::getenv("TERM");
  return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
}

}  // anonymous namespace

OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
  : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
    out_(out) {
}

void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
  out_ << sp;
}

FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
  : SymbolizePrinter(options, isColorfulTty(options, fd)),
    fd_(fd),
    buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {
}

FDSymbolizePrinter::~FDSymbolizePrinter() {
  flush();
}

void FDSymbolizePrinter::doPrint(StringPiece sp) {
  if (buffer_) {
    if (sp.size() > buffer_->tailroom()) {
      flush();
      writeFull(fd_, sp.data(), sp.size());
    } else {
      memcpy(buffer_->writableTail(), sp.data(), sp.size());
      buffer_->append(sp.size());
    }
  } else {
    writeFull(fd_, sp.data(), sp.size());
  }
}

void FDSymbolizePrinter::flush() {
  if (buffer_ && !buffer_->empty()) {
    writeFull(fd_, buffer_->data(), buffer_->length());
    buffer_->clear();
  }
}

FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
  : SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
    file_(file) {
}

void FILESymbolizePrinter::doPrint(StringPiece sp) {
  fwrite(sp.data(), 1, sp.size(), file_);
}

void StringSymbolizePrinter::doPrint(StringPiece sp) {
  buf_.append(sp.data(), sp.size());
}

}  // namespace symbolizer
}  // namespace folly
<commit_msg>Use _r_debug instead of /proc/<pid>/maps for folly::symbolizer<commit_after>/*
 * Copyright 2016 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/experimental/symbolizer/Symbolizer.h>

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits.h>
#include <link.h>
#include <unistd.h>

#ifdef __GNUC__
#include <ext/stdio_filebuf.h>
#include <ext/stdio_sync_filebuf.h>
#endif

#include <folly/Conv.h>
#include <folly/FileUtil.h>
#include <folly/ScopeGuard.h>
#include <folly/String.h>

#include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/Dwarf.h>
#include <folly/experimental/symbolizer/LineReader.h>

/*
 * This is declared in `link.h' on Linux platforms, but apparently not on the
 * Mac version of the file.  It's harmless to declare again, in any case.
 *
 * Note that declaring it with `extern "C"` results in linkage conflicts.
 */
extern struct r_debug _r_debug;

namespace folly {
namespace symbolizer {

namespace {

ElfCache* defaultElfCache() {
  static constexpr size_t defaultCapacity = 500;
  static auto cache = new ElfCache(defaultCapacity);
  return cache;
}

}  // namespace

void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
                          uintptr_t address) {
  clear();
  found = true;

  address += file->getBaseAddress();
  auto sym = file->getDefinitionByAddress(address);
  if (!sym.first) {
    return;
  }

  file_ = file;
  name = file->getSymbolName(sym);

  Dwarf(file.get()).findAddress(address, location);
}

Symbolizer::Symbolizer(ElfCacheBase* cache)
  : cache_(cache ?: defaultElfCache()) {
}

void Symbolizer::symbolize(const uintptr_t* addresses,
                           SymbolizedFrame* frames,
                           size_t addrCount) {
  size_t remaining = 0;
  for (size_t i = 0; i < addrCount; ++i) {
    auto& frame = frames[i];
    if (!frame.found) {
      ++remaining;
      frame.clear();
    }
  }

  if (remaining == 0) {  // we're done
    return;
  }

  if (_r_debug.r_version != 1) {
    return;
  }

  char selfPath[PATH_MAX + 8];
  ssize_t selfSize;
  if ((selfSize = readlink("/proc/self/exe", selfPath, PATH_MAX + 1)) == -1) {
    // Something has gone terribly wrong.
    return;
  }
  selfPath[selfSize] = '\0';

  for (auto lmap = _r_debug.r_map;
       lmap != nullptr && remaining != 0;
       lmap = lmap->l_next) {
    // The empty string is used in place of the filename for the link_map
    // corresponding to the running executable.  Additionally, the `l_addr' is
    // 0 and the link_map appears to be first in the list---but none of this
    // behavior appears to be documented, so checking for the empty string is
    // as good as anything.
    auto const objPath = lmap->l_name[0] != '\0' ? lmap->l_name : selfPath;

    auto const elfFile = cache_->getFile(objPath);
    if (!elfFile) {
      continue;
    }

    // Get the address at which the object is loaded.  We have to use the ELF
    // header for the running executable, since its `l_addr' is zero, but we
    // should use `l_addr' for everything else---in particular, if the object
    // is position-independent, getBaseAddress() (which is p_vaddr) will be 0.
    auto const base = lmap->l_addr != 0
      ? lmap->l_addr
      : elfFile->getBaseAddress();

    for (size_t i = 0; i < addrCount && remaining != 0; ++i) {
      auto& frame = frames[i];
      if (frame.found) {
        continue;
      }

      auto const addr = addresses[i];
      // Get the unrelocated, ELF-relative address.
      auto const adjusted = addr - base;

      if (elfFile->getSectionContainingAddress(adjusted)) {
        frame.set(elfFile, adjusted);
        --remaining;
      }
    }
  }
}

namespace {
constexpr char kHexChars[] = "0123456789abcdef";
constexpr auto kAddressColor = SymbolizePrinter::Color::BLUE;
constexpr auto kFunctionColor = SymbolizePrinter::Color::PURPLE;
constexpr auto kFileColor = SymbolizePrinter::Color::DEFAULT;
}  // namespace

constexpr char AddressFormatter::bufTemplate[];
constexpr std::array<const char*, SymbolizePrinter::Color::NUM>
    SymbolizePrinter::kColorMap;

AddressFormatter::AddressFormatter() {
  memcpy(buf_, bufTemplate, sizeof(buf_));
}

folly::StringPiece AddressFormatter::format(uintptr_t address) {
  // Can't use sprintf, not async-signal-safe
  static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
  char* end = buf_ + sizeof(buf_) - 1 - (16 - 2 * sizeof(uintptr_t));
  char* p = end;
  *p-- = '\0';
  while (address != 0) {
    *p-- = kHexChars[address & 0xf];
    address >>= 4;
  }

  return folly::StringPiece(buf_, end);
}

void SymbolizePrinter::print(uintptr_t address, const SymbolizedFrame& frame) {
  if (options_ & TERSE) {
    printTerse(address, frame);
    return;
  }

  SCOPE_EXIT { color(Color::DEFAULT); };

  if (!(options_ & NO_FRAME_ADDRESS)) {
    color(kAddressColor);

    AddressFormatter formatter;
    doPrint(formatter.format(address));
  }

  const char padBuf[] = "                       ";
  folly::StringPiece pad(padBuf,
                         sizeof(padBuf) - 1 - (16 - 2 * sizeof(uintptr_t)));

  color(kFunctionColor);
  if (!frame.found) {
    doPrint(" (not found)");
    return;
  }

  if (!frame.name || frame.name[0] == '\0') {
    doPrint(" (unknown)");
  } else {
    char demangledBuf[2048];
    demangle(frame.name, demangledBuf, sizeof(demangledBuf));
    doPrint(" ");
    doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  }

  if (!(options_ & NO_FILE_AND_LINE)) {
    color(kFileColor);
    char fileBuf[PATH_MAX];
    fileBuf[0] = '\0';
    if (frame.location.hasFileAndLine) {
      frame.location.file.toBuffer(fileBuf, sizeof(fileBuf));
      doPrint("\n");
      doPrint(pad);
      doPrint(fileBuf);

      char buf[22];
      uint32_t n = uint64ToBufferUnsafe(frame.location.line, buf);
      doPrint(":");
      doPrint(StringPiece(buf, n));
    }

    if (frame.location.hasMainFile) {
      char mainFileBuf[PATH_MAX];
      mainFileBuf[0] = '\0';
      frame.location.mainFile.toBuffer(mainFileBuf, sizeof(mainFileBuf));
      if (!frame.location.hasFileAndLine || strcmp(fileBuf, mainFileBuf)) {
        doPrint("\n");
        doPrint(pad);
        doPrint("-> ");
        doPrint(mainFileBuf);
      }
    }
  }
}

void SymbolizePrinter::color(SymbolizePrinter::Color color) {
  if ((options_ & COLOR) == 0 &&
      ((options_ & COLOR_IF_TTY) == 0 || !isTty_)) {
    return;
  }
  if (color < 0 || color >= kColorMap.size()) {
    return;
  }
  doPrint(kColorMap[color]);
}

void SymbolizePrinter::println(uintptr_t address,
                               const SymbolizedFrame& frame) {
  print(address, frame);
  doPrint("\n");
}

void SymbolizePrinter::printTerse(uintptr_t address,
                                  const SymbolizedFrame& frame) {
  if (frame.found && frame.name && frame.name[0] != '\0') {
    char demangledBuf[2048] = {0};
    demangle(frame.name, demangledBuf, sizeof(demangledBuf));
    doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
  } else {
    // Can't use sprintf, not async-signal-safe
    static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
    char buf[] = "0x0000000000000000";
    char* end = buf + sizeof(buf) - 1 - (16 - 2 * sizeof(uintptr_t));
    char* p = end;
    *p-- = '\0';
    while (address != 0) {
      *p-- = kHexChars[address & 0xf];
      address >>= 4;
    }
    doPrint(StringPiece(buf, end));
  }
}

void SymbolizePrinter::println(const uintptr_t* addresses,
                               const SymbolizedFrame* frames,
                               size_t frameCount) {
  for (size_t i = 0; i < frameCount; ++i) {
    println(addresses[i], frames[i]);
  }
}

namespace {

int getFD(const std::ios& stream) {
#ifdef __GNUC__
  std::streambuf* buf = stream.rdbuf();
  using namespace __gnu_cxx;

  {
    auto sbuf = dynamic_cast<stdio_sync_filebuf<char>*>(buf);
    if (sbuf) {
      return fileno(sbuf->file());
    }
  }
  {
    auto sbuf = dynamic_cast<stdio_filebuf<char>*>(buf);
    if (sbuf) {
      return sbuf->fd();
    }
  }
#endif  // __GNUC__
  return -1;
}

bool isColorfulTty(int options, int fd) {
  if ((options & SymbolizePrinter::TERSE) != 0 ||
      (options & SymbolizePrinter::COLOR_IF_TTY) == 0 ||
      fd < 0 || !::isatty(fd)) {
    return false;
  }
  auto term = ::getenv("TERM");
  return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
}

}  // anonymous namespace

OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
  : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
    out_(out) {
}

void OStreamSymbolizePrinter::doPrint(StringPiece sp) {
  out_ << sp;
}

FDSymbolizePrinter::FDSymbolizePrinter(int fd, int options, size_t bufferSize)
  : SymbolizePrinter(options, isColorfulTty(options, fd)),
    fd_(fd),
    buffer_(bufferSize ? IOBuf::create(bufferSize) : nullptr) {
}

FDSymbolizePrinter::~FDSymbolizePrinter() {
  flush();
}

void FDSymbolizePrinter::doPrint(StringPiece sp) {
  if (buffer_) {
    if (sp.size() > buffer_->tailroom()) {
      flush();
      writeFull(fd_, sp.data(), sp.size());
    } else {
      memcpy(buffer_->writableTail(), sp.data(), sp.size());
      buffer_->append(sp.size());
    }
  } else {
    writeFull(fd_, sp.data(), sp.size());
  }
}

void FDSymbolizePrinter::flush() {
  if (buffer_ && !buffer_->empty()) {
    writeFull(fd_, buffer_->data(), buffer_->length());
    buffer_->clear();
  }
}

FILESymbolizePrinter::FILESymbolizePrinter(FILE* file, int options)
  : SymbolizePrinter(options, isColorfulTty(options, fileno(file))),
    file_(file) {
}

void FILESymbolizePrinter::doPrint(StringPiece sp) {
  fwrite(sp.data(), 1, sp.size(), file_);
}

void StringSymbolizePrinter::doPrint(StringPiece sp) {
  buf_.append(sp.data(), sp.size());
}

}  // namespace symbolizer
}  // namespace folly
<|endoftext|>