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

#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  Waiter(Browser* browser)
      : browser_(browser) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() {}

 protected:

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    InitStatusAreaMocks();
    InitMockScreenLockLibrary();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  ui_test_utils::WaitForNotification(
      NotificationType::SCREEN_LOCK_STATE_CHANGED);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) {
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            base::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();

  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  ui_test_utils::WaitForNotification(
      NotificationType::SCREEN_LOCK_STATE_CHANGED);
  EXPECT_TRUE(tester->IsLocked());

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<commit_msg>add expectations that were removed from setup in other cl.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  Waiter(Browser* browser)
      : browser_(browser) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() {}

 protected:

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    InitStatusAreaMocks();
    InitMockScreenLockLibrary();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  ui_test_utils::WaitForNotification(
      NotificationType::SCREEN_LOCK_STATE_CHANGED);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            base::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();

  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  ui_test_utils::WaitForNotification(
      NotificationType::SCREEN_LOCK_STATE_CHANGED);
  EXPECT_TRUE(tester->IsLocked());

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

#include "cql3/column_identifier.hh"

namespace cql3 {

::shared_ptr<column_identifier> prepare_column_identifier(schema_ptr s) {
#if 0
            AbstractType<?> comparator = cfm.comparator.asAbstractType();
            if (cfm.getIsDense() || comparator instanceof CompositeType || comparator instanceof UTF8Type)
                return new ColumnIdentifier(text, true);

            // We have a Thrift-created table with a non-text comparator.  We need to parse column names with the comparator
            // to get the correct ByteBuffer representation.  However, this doesn't apply to key aliases, so we need to
            // make a special check for those and treat them normally.  See CASSANDRA-8178.
            ByteBuffer bufferName = ByteBufferUtil.bytes(text);
            for (ColumnDefinition def : cfm.partitionKeyColumns())
            {
                if (def.name.bytes.equals(bufferName))
                    return new ColumnIdentifier(text, true);
            }
            return new ColumnIdentifier(comparator.fromString(rawText), text);
#endif
    throw std::runtime_error("not implemented");
}

std::ostream& operator<<(std::ostream& out, const column_identifier::raw& id) {
    return out << id._text;
}

}
<commit_msg>cql3: Implement column_identifier::raw::prepare()<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

#include "cql3/column_identifier.hh"

namespace cql3 {

::shared_ptr<column_identifier>
column_identifier::raw::prepare_column_identifier(schema_ptr schema) {
    if (schema->regular_column_name_type == utf8_type) {
        return ::make_shared<column_identifier>(_text, true);
    }

    // We have a Thrift-created table with a non-text comparator.  We need to parse column names with the comparator
    // to get the correct ByteBuffer representation.  However, this doesn't apply to key aliases, so we need to
    // make a special check for those and treat them normally.  See CASSANDRA-8178.
    auto text_bytes = to_bytes(_text);
    auto def = schema->get_column_definition(text_bytes);
    if (def) {
        return ::make_shared<column_identifier>(std::move(text_bytes), _text);
    }

    return ::make_shared<column_identifier>(schema->regular_column_name_type->from_string(_raw_text), _text);
}

std::ostream& operator<<(std::ostream& out, const column_identifier::raw& id) {
    return out << id._text;
}

}
<|endoftext|>


<commit_before><commit_msg>Disabling more IndexedDBBrowserTests because of time outs. BUG=63675 TEST=none TBR=jochen@chromium.org Review URL: http://codereview.chromium.org/5201004<commit_after><|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX63T グループ・SCI 定義 @n
			Copyright 2013 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/io_utils.hpp"
#include "RX63T/peripheral.hpp"
#include "RX63T/icu.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCIc, SCId 定義基底クラス
		@param[in]	base	ベース・アドレス
		@param[in]	t		ペリフェラル型
		@param[in]	txv		送信ベクター
		@param[in]	rxv		受信ベクター
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral t, ICU::VECTOR txv, ICU::VECTOR rxv>
	struct sci_t {

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルモードレジスタ (SMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x00> smr_io;
		struct smr_t : public smr_io {
			using smr_io::operator =;
			using smr_io::operator ();
			using smr_io::operator |=;
			using smr_io::operator &=;

			bits_rw_t<smr_io, bitpos::B0, 2>  CKS;
			bit_rw_t< smr_io, bitpos::B2>	  MP;
			bit_rw_t< smr_io, bitpos::B3>	  STOP;
			bit_rw_t< smr_io, bitpos::B4>	  PM;
			bit_rw_t< smr_io, bitpos::B5>	  PE;
			bit_rw_t< smr_io, bitpos::B6>	  CHR;
			bit_rw_t< smr_io, bitpos::B7>	  CM;

			bits_rw_t< smr_io, bitpos::B2, 2> BCP;
			bit_rw_t< smr_io, bitpos::B6>	  BLK;
			bit_rw_t< smr_io, bitpos::B7>	  GM;
		};
		static smr_t SMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ビットレートレジスタ (BRR)
		*/
		//-----------------------------------------------------------------//
		static rw8_t<base + 0x01> BRR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルコントロールレジスタ (SCR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x02> scr_io;
		struct scr_t : public scr_io {
			using scr_io::operator =;
			using scr_io::operator ();
			using scr_io::operator |=;
			using scr_io::operator &=;

			bits_rw_t<scr_io, bitpos::B0, 2>	CKE;
			bit_rw_t< scr_io, bitpos::B2>	TEIE;
			bit_rw_t< scr_io, bitpos::B3>	MPIE;
			bit_rw_t< scr_io, bitpos::B4>	RE;
			bit_rw_t< scr_io, bitpos::B5>	TE;
			bit_rw_t< scr_io, bitpos::B6>	RIE;
			bit_rw_t< scr_io, bitpos::B7>	TIE;
		};
		static scr_t SCR;

		//-----------------------------------------------------------------//
		/*!
			@brief  トランスミットデータレジスタ (TDR)
		*/
		//-----------------------------------------------------------------//
		static rw8_t<base + 0x03> TDR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルステータスレジスタ (SSR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x04> ssr_io;
		struct ssr_t : public ssr_io {
			using ssr_io::operator =;
			using ssr_io::operator ();
			using ssr_io::operator |=;
			using ssr_io::operator &=;

			bit_rw_t<ssr_io, bitpos::B0>	MPBT;
			bit_rw_t<ssr_io, bitpos::B1>	MPB;
			bit_rw_t<ssr_io, bitpos::B2>	TEND;
			bit_rw_t<ssr_io, bitpos::B3>	PER;
			bit_rw_t<ssr_io, bitpos::B4>	FER;
			bit_rw_t<ssr_io, bitpos::B4>	ERS;
			bit_rw_t<ssr_io, bitpos::B5>	ORER;
		};
		static ssr_t SSR;

		//-----------------------------------------------------------------//
		/*!
			@brief  レシーブデータレジスタ (RDR)
		*/
		//-----------------------------------------------------------------//
		static ro8_t<base + 0x05> RDR;

		//-----------------------------------------------------------------//
		/*!
			@brief  スマートカードモードレジスタ (SCMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x06> scmr_io;
		struct scmr_t : public scmr_io {
			using scmr_io::operator =;
			using scmr_io::operator ();
			using scmr_io::operator |=;
			using scmr_io::operator &=;

			bit_rw_t<scmr_io, bitpos::B0>	SMIF;
			bit_rw_t<scmr_io, bitpos::B2>	SINV;
			bit_rw_t<scmr_io, bitpos::B3>	SDIR;
			bit_rw_t<scmr_io, bitpos::B7>	BCP2;
		};
		static scmr_t SCMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル拡張レジスタ (SEMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x07> semr_io;
		struct semr_t : public semr_io {
			using semr_io::operator =;
			using semr_io::operator ();
			using semr_io::operator |=;
			using semr_io::operator &=;

			bit_rw_t<semr_io, bitpos::B0>	ACS0;
			bit_rw_t<semr_io, bitpos::B4>	ABCS;
			bit_rw_t<semr_io, bitpos::B5>	NFEN;
		};
		static semr_t SEMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ノイズフィルタ設定レジスタ (SNFR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x08> snfr_io;
		struct snfr_t : public snfr_io {
			using snfr_io::operator =;
			using snfr_io::operator ();
			using snfr_io::operator |=;
			using snfr_io::operator &=;

			bits_rw_t<snfr_io, bitpos::B0, 3>	NFCS;
		};
		static snfr_t SNFR;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ１ (SIMR1)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x09> simr1_io;
		struct simr1_t : public simr1_io {
			using simr1_io::operator =;
			using simr1_io::operator ();
			using simr1_io::operator |=;
			using simr1_io::operator &=;

			bit_rw_t< simr1_io, bitpos::B0>	    IICM;
			bits_rw_t<simr1_io, bitpos::B3, 5>	IICDL;
		};
		static simr1_t SIMR1;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ２ (SIMR2)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0a> simr2_io;
		struct simr2_t : public simr2_io {
			using simr2_io::operator =;
			using simr2_io::operator ();
			using simr2_io::operator |=;
			using simr2_io::operator &=;

			bit_rw_t<simr2_io, bitpos::B0>	    IICINTM;
			bit_rw_t<simr2_io, bitpos::B1>	    IICCSC;
			bit_rw_t<simr2_io, bitpos::B5>	    IICACKT;
		};
		static simr2_t SIMR2;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ３ (SIMR3)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0b> simr3_io;
		struct simr3_t : public simr3_io {
			using simr3_io::operator =;
			using simr3_io::operator ();
			using simr3_io::operator |=;
			using simr3_io::operator &=;

			bit_rw_t< simr3_io, bitpos::B0>	    IICSTAREQ;
			bit_rw_t< simr3_io, bitpos::B1>	    IICRSTAREQ;
			bit_rw_t< simr3_io, bitpos::B2>	    IICSTPREQ;
			bit_rw_t< simr3_io, bitpos::B3>	    IICSTIF;
			bits_rw_t<simr3_io, bitpos::B4, 2>	IICSDAS;
			bits_rw_t<simr3_io, bitpos::B6, 2>	IICSCLS;
		};
		static simr3_t SIMR3;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C ステータスレジスタ (SISR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0c> sisr_io;
		struct sisr_t : public sisr_io {
			using sisr_io::operator =;
			using sisr_io::operator ();
			using sisr_io::operator |=;
			using sisr_io::operator &=;

			bit_rw_t<sisr_io, bitpos::B0>	IICACKR;
		};
		static sisr_t SISR;

		//-----------------------------------------------------------------//
		/*!
			@brief  SPI モードレジスタ (SPMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0d> spmr_io;
		struct spmr_t : public spmr_io {
			using spmr_io::operator =;
			using spmr_io::operator ();
			using spmr_io::operator |=;
			using spmr_io::operator &=;

			bit_rw_t<spmr_io, bitpos::B0>	SSE;
			bit_rw_t<spmr_io, bitpos::B1>	CTSE;
			bit_rw_t<spmr_io, bitpos::B2>	MSS;
			bit_rw_t<spmr_io, bitpos::B4>	MFF;
			bit_rw_t<spmr_io, bitpos::B6>	CKPOL;
			bit_rw_t<spmr_io, bitpos::B7>	CKPH;
		};
		static spmr_t SPMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  拡張シリアルモード有効レジスタ (ESMER) @n
					※SIC12 にのみ有効なレジスタ
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x20> esmer_io;
		struct esmer_t : public esmer_io {
			using esmer_io::operator =;
			using esmer_io::operator ();
			using esmer_io::operator |=;
			using esmer_io::operator &=;

			bit_rw_t<esmer_io, bitpos::B0>	ESME;
		};
		static esmer_t ESMER;

		//-----------------------------------------------------------------//
		/*!
			@brief  チャネルを返す
			@return チャネル（０、１、２、３、１２）
		*/
		//-----------------------------------------------------------------//
		static uint32_t get_chanel() {
			if(base == 0x0008b300) return 12;
			return (base >> 5) & 3;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return t; }

		//-----------------------------------------------------------------//
		/*!
			@brief  送信割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_tx_vec() { return txv; }

		//-----------------------------------------------------------------//
		/*!
			@brief  受信割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_rx_vec() { return rxv; }
	};

	typedef sci_t<0x0008a000, peripheral::SCI0, ICU::VECTOR::TXI0, ICU::VECTOR::RXI0> SCI0;
	typedef sci_t<0x0008a020, peripheral::SCI1, ICU::VECTOR::TXI1, ICU::VECTOR::RXI1> SCI1;
	typedef sci_t<0x0008a040, peripheral::SCI2, ICU::VECTOR::TXI2, ICU::VECTOR::RXI2> SCI2;
	typedef sci_t<0x0008a060, peripheral::SCI3, ICU::VECTOR::TXI3, ICU::VECTOR::RXI3> SCI3;

//	typedef sci_t<0x0008b300> SCI12;
}
<commit_msg>update TE interrupt<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX63T グループ・SCI 定義 @n
			Copyright 2013 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/io_utils.hpp"
#include "RX63T/peripheral.hpp"
#include "RX63T/icu.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCIc, SCId 定義基底クラス
		@param[in]	base	ベース・アドレス
		@param[in]	t		ペリフェラル型
		@param[in]	rxv		受信ベクター
		@param[in]	tev		送信ベクター
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral t, ICU::VECTOR rxv, ICU::VECTOR tev>
	struct sci_t {

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルモードレジスタ (SMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x00> smr_io;
		struct smr_t : public smr_io {
			using smr_io::operator =;
			using smr_io::operator ();
			using smr_io::operator |=;
			using smr_io::operator &=;

			bits_rw_t<smr_io, bitpos::B0, 2>  CKS;
			bit_rw_t< smr_io, bitpos::B2>	  MP;
			bit_rw_t< smr_io, bitpos::B3>	  STOP;
			bit_rw_t< smr_io, bitpos::B4>	  PM;
			bit_rw_t< smr_io, bitpos::B5>	  PE;
			bit_rw_t< smr_io, bitpos::B6>	  CHR;
			bit_rw_t< smr_io, bitpos::B7>	  CM;

			bits_rw_t< smr_io, bitpos::B2, 2> BCP;
			bit_rw_t< smr_io, bitpos::B6>	  BLK;
			bit_rw_t< smr_io, bitpos::B7>	  GM;
		};
		static smr_t SMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ビットレートレジスタ (BRR)
		*/
		//-----------------------------------------------------------------//
		static rw8_t<base + 0x01> BRR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルコントロールレジスタ (SCR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x02> scr_io;
		struct scr_t : public scr_io {
			using scr_io::operator =;
			using scr_io::operator ();
			using scr_io::operator |=;
			using scr_io::operator &=;

			bits_rw_t<scr_io, bitpos::B0, 2>	CKE;
			bit_rw_t< scr_io, bitpos::B2>	TEIE;
			bit_rw_t< scr_io, bitpos::B3>	MPIE;
			bit_rw_t< scr_io, bitpos::B4>	RE;
			bit_rw_t< scr_io, bitpos::B5>	TE;
			bit_rw_t< scr_io, bitpos::B6>	RIE;
			bit_rw_t< scr_io, bitpos::B7>	TIE;
		};
		static scr_t SCR;

		//-----------------------------------------------------------------//
		/*!
			@brief  トランスミットデータレジスタ (TDR)
		*/
		//-----------------------------------------------------------------//
		static rw8_t<base + 0x03> TDR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアルステータスレジスタ (SSR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x04> ssr_io;
		struct ssr_t : public ssr_io {
			using ssr_io::operator =;
			using ssr_io::operator ();
			using ssr_io::operator |=;
			using ssr_io::operator &=;

			bit_rw_t<ssr_io, bitpos::B0>	MPBT;
			bit_rw_t<ssr_io, bitpos::B1>	MPB;
			bit_rw_t<ssr_io, bitpos::B2>	TEND;
			bit_rw_t<ssr_io, bitpos::B3>	PER;
			bit_rw_t<ssr_io, bitpos::B4>	FER;
			bit_rw_t<ssr_io, bitpos::B4>	ERS;
			bit_rw_t<ssr_io, bitpos::B5>	ORER;
		};
		static ssr_t SSR;

		//-----------------------------------------------------------------//
		/*!
			@brief  レシーブデータレジスタ (RDR)
		*/
		//-----------------------------------------------------------------//
		static ro8_t<base + 0x05> RDR;

		//-----------------------------------------------------------------//
		/*!
			@brief  スマートカードモードレジスタ (SCMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x06> scmr_io;
		struct scmr_t : public scmr_io {
			using scmr_io::operator =;
			using scmr_io::operator ();
			using scmr_io::operator |=;
			using scmr_io::operator &=;

			bit_rw_t<scmr_io, bitpos::B0>	SMIF;
			bit_rw_t<scmr_io, bitpos::B2>	SINV;
			bit_rw_t<scmr_io, bitpos::B3>	SDIR;
			bit_rw_t<scmr_io, bitpos::B7>	BCP2;
		};
		static scmr_t SCMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル拡張レジスタ (SEMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x07> semr_io;
		struct semr_t : public semr_io {
			using semr_io::operator =;
			using semr_io::operator ();
			using semr_io::operator |=;
			using semr_io::operator &=;

			bit_rw_t<semr_io, bitpos::B0>	ACS0;
			bit_rw_t<semr_io, bitpos::B4>	ABCS;
			bit_rw_t<semr_io, bitpos::B5>	NFEN;
		};
		static semr_t SEMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ノイズフィルタ設定レジスタ (SNFR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x08> snfr_io;
		struct snfr_t : public snfr_io {
			using snfr_io::operator =;
			using snfr_io::operator ();
			using snfr_io::operator |=;
			using snfr_io::operator &=;

			bits_rw_t<snfr_io, bitpos::B0, 3>	NFCS;
		};
		static snfr_t SNFR;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ１ (SIMR1)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x09> simr1_io;
		struct simr1_t : public simr1_io {
			using simr1_io::operator =;
			using simr1_io::operator ();
			using simr1_io::operator |=;
			using simr1_io::operator &=;

			bit_rw_t< simr1_io, bitpos::B0>	    IICM;
			bits_rw_t<simr1_io, bitpos::B3, 5>	IICDL;
		};
		static simr1_t SIMR1;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ２ (SIMR2)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0a> simr2_io;
		struct simr2_t : public simr2_io {
			using simr2_io::operator =;
			using simr2_io::operator ();
			using simr2_io::operator |=;
			using simr2_io::operator &=;

			bit_rw_t<simr2_io, bitpos::B0>	    IICINTM;
			bit_rw_t<simr2_io, bitpos::B1>	    IICCSC;
			bit_rw_t<simr2_io, bitpos::B5>	    IICACKT;
		};
		static simr2_t SIMR2;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C モードレジスタ３ (SIMR3)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0b> simr3_io;
		struct simr3_t : public simr3_io {
			using simr3_io::operator =;
			using simr3_io::operator ();
			using simr3_io::operator |=;
			using simr3_io::operator &=;

			bit_rw_t< simr3_io, bitpos::B0>	    IICSTAREQ;
			bit_rw_t< simr3_io, bitpos::B1>	    IICRSTAREQ;
			bit_rw_t< simr3_io, bitpos::B2>	    IICSTPREQ;
			bit_rw_t< simr3_io, bitpos::B3>	    IICSTIF;
			bits_rw_t<simr3_io, bitpos::B4, 2>	IICSDAS;
			bits_rw_t<simr3_io, bitpos::B6, 2>	IICSCLS;
		};
		static simr3_t SIMR3;

		//-----------------------------------------------------------------//
		/*!
			@brief  I2C ステータスレジスタ (SISR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0c> sisr_io;
		struct sisr_t : public sisr_io {
			using sisr_io::operator =;
			using sisr_io::operator ();
			using sisr_io::operator |=;
			using sisr_io::operator &=;

			bit_rw_t<sisr_io, bitpos::B0>	IICACKR;
		};
		static sisr_t SISR;

		//-----------------------------------------------------------------//
		/*!
			@brief  SPI モードレジスタ (SPMR)
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x0d> spmr_io;
		struct spmr_t : public spmr_io {
			using spmr_io::operator =;
			using spmr_io::operator ();
			using spmr_io::operator |=;
			using spmr_io::operator &=;

			bit_rw_t<spmr_io, bitpos::B0>	SSE;
			bit_rw_t<spmr_io, bitpos::B1>	CTSE;
			bit_rw_t<spmr_io, bitpos::B2>	MSS;
			bit_rw_t<spmr_io, bitpos::B4>	MFF;
			bit_rw_t<spmr_io, bitpos::B6>	CKPOL;
			bit_rw_t<spmr_io, bitpos::B7>	CKPH;
		};
		static spmr_t SPMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  拡張シリアルモード有効レジスタ (ESMER) @n
					※SIC12 にのみ有効なレジスタ
		*/
		//-----------------------------------------------------------------//
		typedef rw8_t<base + 0x20> esmer_io;
		struct esmer_t : public esmer_io {
			using esmer_io::operator =;
			using esmer_io::operator ();
			using esmer_io::operator |=;
			using esmer_io::operator &=;

			bit_rw_t<esmer_io, bitpos::B0>	ESME;
		};
		static esmer_t ESMER;

		//-----------------------------------------------------------------//
		/*!
			@brief  チャネルを返す
			@return チャネル（０、１、２、３、１２）
		*/
		//-----------------------------------------------------------------//
		static uint32_t get_chanel() {
			if(base == 0x0008b300) return 12;
			return (base >> 5) & 3;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return t; }

		//-----------------------------------------------------------------//
		/*!
			@brief  受信割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_rx_vec() { return rxv; }

		//-----------------------------------------------------------------//
		/*!
			@brief  送信割り込みベクターを返す
			@return ベクター型
		*/
		//-----------------------------------------------------------------//
		static ICU::VECTOR get_te_vec() { return tev; }
	};

	typedef sci_t<0x0008a000, peripheral::SCI0, ICU::VECTOR::RXI0, ICU::VECTOR::TEI0> SCI0;
	typedef sci_t<0x0008a020, peripheral::SCI1, ICU::VECTOR::RXI1, ICU::VECTOR::TEI1> SCI1;
	typedef sci_t<0x0008a040, peripheral::SCI2, ICU::VECTOR::RXI2, ICU::VECTOR::TEI2> SCI2;
	typedef sci_t<0x0008a060, peripheral::SCI3, ICU::VECTOR::RXI3, ICU::VECTOR::TEI3> SCI3;

//	typedef sci_t<0x0008b300> SCI12;
}
<|endoftext|>


<commit_before>#include <fstream>
#include <stdexcept>
#include <cstdint>
#include <tuple>
#include <cstdlib>
#include <ctime>
#include <iostream>

#include "VM.hpp"
#include "Keyboard.hpp"

using namespace Chip8;

const std::chrono::milliseconds VM::runningRate(1000 / 840); // 840Hz

VM::VM(Backend& backend, std::istream& stream) :
	mBackend(backend)
{
	loadProgram(stream);
	init();
}

VM::VM(Backend& backend, const std::string& filename) :
	mBackend(backend)
{
	std::ifstream file(filename, std::ios::binary);
	if (!file)
		throw std::runtime_error("error opening file: " + filename);

	loadProgram(file);
	init();
}

void VM::init()
{
	srand(time(nullptr));

	mSoundTimer.setNonZeroCallback([&] { mBackend.playBeep(); });
	mSoundTimer.setZeroCallback([&] { mBackend.stopBeep(); });
	mDisplay.clear();
}

void VM::previousInst()
{
	mRegisters.pc -= OPCODE_SIZE;
}

void VM::nextInst()
{
	mRegisters.pc += OPCODE_SIZE;
}

void VM::loadProgram(std::istream& stream)
{
	constexpr int BUFFER_SIZE = 512;

	char buffer[BUFFER_SIZE];
	Memory::addr_t address = Memory::PROGRAM_START_ADDRESS;

	while (!stream.eof()) {
		stream.read(buffer, BUFFER_SIZE);
		const auto count = stream.gcount();
		mMemory.write(buffer, count, address);
		address += count;
	}
}

void VM::run()
{
	auto runningTime = mBackend.getTicks();
	auto timersTime = runningTime;

	mRegisters.pc = Memory::PROGRAM_START_ADDRESS;

	while (!mBackend.quit()) {
		const auto current = mBackend.getTicks();

		auto delta = current - runningRate;
		if (delta >= runningRate) {
			runExec();
			runningTime = current;
		}

		delta = current - timersTime;
		if (delta >= Timer::resolution) {
			mDelayTimer.update(delta);
			mSoundTimer.update(delta);
			timersTime = current;
		}

		mBackend.delay(std::chrono::milliseconds(runningRate));
	}
}

void VM::runExec()
{
	uint16_t opCode = mMemory.readOpCode(mRegisters.pc);
	/* std::cout << '[' << std::hex << mRegisters.pc << "] opcode: 0x" << std::hex << opCode << " (" << std::dec << opCode << ")\n"; */
	nextInst();

	const auto opCodeTuple = std::make_tuple(
		opCode >> 12,
		(opCode >> 8) & 0xf,
		(opCode >> 4) & 0xf,
		opCode & 0xf
	);

	const auto x = std::get<1>(opCodeTuple);
	const auto y = std::get<2>(opCodeTuple);

	switch (std::get<0>(opCodeTuple)) {
		case 0:
			if (opCode == 0x00e0) {
				mDisplay.clear();
				mBackend.clearDisplay();
			}
			else if (opCode == 0x00ee) {
				execReturn();
			}
			// ignore call to RCA 1802 program
			break;
		case 1:
			// jump
			mRegisters.pc = opCode & 0xfff;
			break;
		case 2:
			// call
			mStack.push(mRegisters.pc);
			mRegisters.pc = opCode & 0xfff;
			break;
		case 3:
			if (mRegisters.V[x] == (opCode & 0xff))
				nextInst();
			break;
		case 4:
			if (mRegisters.V[x] != (opCode & 0xff))
				nextInst();
			break;
		case 5:
			if (std::get<3>(opCodeTuple) != 0)
				throw InvalidInstruction(opCode);
			if (mRegisters.V[x] == mRegisters.V[y])
				nextInst();
			break;
		case 6:
			mRegisters.V[x] = opCode & 0xff;
			break;
		case 7:
			mRegisters.V[x] += opCode & 0xff;
			break;
		case 8:
			handle8xyOps(opCode, x, y, std::get<3>(opCodeTuple));
			break;
		case 9:
			if (std::get<3>(opCodeTuple) != 0)
				throw InvalidInstruction(opCode);
			if (mRegisters.V[x] != mRegisters.V[y])
				nextInst();
			break;
		case 0xa:
			mRegisters.I = opCode & 0xfff;
			break;
		case 0xb:
			mRegisters.pc = mRegisters.V[0] + (opCode & 0xfff);
			break;
		case 0xc:
			mRegisters.V[x] = (rand() % 256) & (opCode & 0xff);
			break;
		case 0xd:
			mRegisters.V[0xf] = execDraw(mRegisters.V[x], mRegisters.V[y], opCode & 0xf);
			break;
		case 0xe:
			execKeyCheck(x, opCode);
			break;
		case 0xf:
			handleFxOps(opCode, x);
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::handle8xyOps(uint16_t opCode, uint8_t x, uint8_t y, uint8_t LSHB)
{
	auto& Vx = mRegisters.V[x];
	auto& Vy = mRegisters.V[y];
	auto& Vf = mRegisters.V[0xf];

	switch (LSHB) {
		case 0:
			Vx = Vy;
			break;
		case 1:
			Vx |= Vy;
			break;
		case 2:
			Vx &= Vy;
			break;
		case 3:
			Vx ^= Vy;
			break;
		case 4:
			Vx += Vy;
			// carry
			Vf = (Vx < Vy);
			break;
		case 5:
			// not borrow
			Vf = (Vx > Vy);
			Vx -= Vy;
			break;
		case 6:
			Vf = Vx & 1;
			Vx >>= 1;
			break;
		case 7:
			// not borrow
			Vf = (Vy > Vx);
			Vx = Vy - Vx;
			break;
		case 0xe:
			Vf = Vx >> 7;
			Vx <<= 1;
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::handleFxOps(uint16_t opCode, uint8_t x)
{
	switch (opCode & 0xff) {
		case 0x07:
			mRegisters.V[x] = mDelayTimer.getValue();
			break;
		case 0x0a:
			execGetKey(x);
			break;
		case 0x15:
			mDelayTimer.setValue(mRegisters.V[x]);
			break;
		case 0x18:
			mSoundTimer.setValue(mRegisters.V[x]);
		case 0x1e:
			mRegisters.I += mRegisters.V[x];
			mRegisters.V[0xf] = (mRegisters.I > 0xfff);
			break;
		case 0x29:
			mRegisters.I = mMemory.getCharacterSpriteAddress(mRegisters.V[x]);
			break;
		case 0x33:
			mMemory.write(static_cast<uint8_t>((mRegisters.V[x] / 100) % 10), mRegisters.I);
			mMemory.write(static_cast<uint8_t>((mRegisters.V[x] / 10) % 10), mRegisters.I + 1);
			mMemory.write(static_cast<uint8_t>(mRegisters.V[x] % 10), mRegisters.I + 2);
			break;
		case 0x55:
			execRegDump(x);
			break;
		case 0x65:
			execRegLoad(x);
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::execRegDump(uint8_t x)
{
	for (int i = 0; i <= x; ++i)
		mMemory.write(mRegisters.V[i], mRegisters.I + i);
}

void VM::execRegLoad(uint8_t x)
{
	for (int i = 0; i <= x; ++i)
		mRegisters.V[i] = mMemory.readUint8(mRegisters.I + i);
}

void VM::execReturn()
{
	mRegisters.pc = mStack.top();
	mStack.pop();
}

void VM::execGetKey(uint8_t x)
{
	Key key = mBackend.waitKey();

	if (key == Key::KEY_NONE)
		previousInst();
	else
		mRegisters.V[x] = key;
}

void VM::execKeyCheck(uint8_t x, uint16_t opCode)
{
	const bool pressed = mBackend.keyIsPressed(static_cast<Key>(mRegisters.V[x]));
	bool expected;

	switch (opCode & 0xff) {
		case 0x9e:
			expected = true;
			break;
		case 0xa1:
			expected = false;
			break;
		default:
			throw InvalidInstruction(opCode);
	}

	if (pressed == expected)
		nextInst();
}

bool VM::execDraw(uint8_t x, uint8_t y, uint8_t n)
{
	bool collision = false;

	for (int i = 0; i < n; ++i) {
		uint8_t sprite = mMemory.readUint8(mRegisters.I + i);
		/* const uint8_t y_ = (y + i) % Display::HEIGHT; */
		const uint8_t y_ = (y + i);

		if (y_ < Display::HEIGHT) {
			for (unsigned int j = 0; j < Display::SPRITE_WIDTH; ++j) {
				/* const uint8_t x_ = (x + j) % Display::WIDTH; */
				const uint8_t x_ = (x + j);

				if (x_ < Display::WIDTH) {
					const bool pixel = (sprite >> 7) & 1;

					if (pixel && mDisplay.flipPixel(x_, y_))
						collision = true;

					sprite <<= 1;
				}
			}
		}
	}

	mBackend.display(mDisplay);

	return collision;
}

/*
 * InvalidInstruction exception
 */
VM::InvalidInstruction::InvalidInstruction(uint16_t opCode) :
	std::runtime_error("Invalid OpCode: " + opCodeToHexStr(opCode))
{
}

std::string VM::InvalidInstruction::opCodeToHexStr(uint16_t opCode)
{
	std::stringstream stream;
	stream << "0x" << std::setfill('0') << std::setw(sizeof(opCode) * 2)
		<< std::hex << opCode;

	return stream.str();
}
<commit_msg>forgot break<commit_after>#include <fstream>
#include <stdexcept>
#include <cstdint>
#include <tuple>
#include <cstdlib>
#include <ctime>
#include <iostream>

#include "VM.hpp"
#include "Keyboard.hpp"

using namespace Chip8;

const std::chrono::milliseconds VM::runningRate(1000 / 840); // 840Hz

VM::VM(Backend& backend, std::istream& stream) :
	mBackend(backend)
{
	loadProgram(stream);
	init();
}

VM::VM(Backend& backend, const std::string& filename) :
	mBackend(backend)
{
	std::ifstream file(filename, std::ios::binary);
	if (!file)
		throw std::runtime_error("error opening file: " + filename);

	loadProgram(file);
	init();
}

void VM::init()
{
	srand(time(nullptr));

	mSoundTimer.setNonZeroCallback([&] { mBackend.playBeep(); });
	mSoundTimer.setZeroCallback([&] { mBackend.stopBeep(); });
	mDisplay.clear();
}

void VM::previousInst()
{
	mRegisters.pc -= OPCODE_SIZE;
}

void VM::nextInst()
{
	mRegisters.pc += OPCODE_SIZE;
}

void VM::loadProgram(std::istream& stream)
{
	constexpr int BUFFER_SIZE = 512;

	char buffer[BUFFER_SIZE];
	Memory::addr_t address = Memory::PROGRAM_START_ADDRESS;

	while (!stream.eof()) {
		stream.read(buffer, BUFFER_SIZE);
		const auto count = stream.gcount();
		mMemory.write(buffer, count, address);
		address += count;
	}
}

void VM::run()
{
	auto runningTime = mBackend.getTicks();
	auto timersTime = runningTime;

	mRegisters.pc = Memory::PROGRAM_START_ADDRESS;

	while (!mBackend.quit()) {
		const auto current = mBackend.getTicks();

		auto delta = current - runningRate;
		if (delta >= runningRate) {
			runExec();
			runningTime = current;
		}

		delta = current - timersTime;
		if (delta >= Timer::resolution) {
			mDelayTimer.update(delta);
			mSoundTimer.update(delta);
			timersTime = current;
		}

		mBackend.delay(std::chrono::milliseconds(runningRate));
	}
}

void VM::runExec()
{
	uint16_t opCode = mMemory.readOpCode(mRegisters.pc);
	/* std::cout << '[' << std::hex << mRegisters.pc << "] opcode: 0x" << std::hex << opCode << " (" << std::dec << opCode << ")\n"; */
	nextInst();

	const auto opCodeTuple = std::make_tuple(
		opCode >> 12,
		(opCode >> 8) & 0xf,
		(opCode >> 4) & 0xf,
		opCode & 0xf
	);

	const auto x = std::get<1>(opCodeTuple);
	const auto y = std::get<2>(opCodeTuple);

	switch (std::get<0>(opCodeTuple)) {
		case 0:
			if (opCode == 0x00e0) {
				mDisplay.clear();
				mBackend.clearDisplay();
			}
			else if (opCode == 0x00ee) {
				execReturn();
			}
			// ignore call to RCA 1802 program
			break;
		case 1:
			// jump
			mRegisters.pc = opCode & 0xfff;
			break;
		case 2:
			// call
			mStack.push(mRegisters.pc);
			mRegisters.pc = opCode & 0xfff;
			break;
		case 3:
			if (mRegisters.V[x] == (opCode & 0xff))
				nextInst();
			break;
		case 4:
			if (mRegisters.V[x] != (opCode & 0xff))
				nextInst();
			break;
		case 5:
			if (std::get<3>(opCodeTuple) != 0)
				throw InvalidInstruction(opCode);
			if (mRegisters.V[x] == mRegisters.V[y])
				nextInst();
			break;
		case 6:
			mRegisters.V[x] = opCode & 0xff;
			break;
		case 7:
			mRegisters.V[x] += opCode & 0xff;
			break;
		case 8:
			handle8xyOps(opCode, x, y, std::get<3>(opCodeTuple));
			break;
		case 9:
			if (std::get<3>(opCodeTuple) != 0)
				throw InvalidInstruction(opCode);
			if (mRegisters.V[x] != mRegisters.V[y])
				nextInst();
			break;
		case 0xa:
			mRegisters.I = opCode & 0xfff;
			break;
		case 0xb:
			mRegisters.pc = mRegisters.V[0] + (opCode & 0xfff);
			break;
		case 0xc:
			mRegisters.V[x] = (rand() % 256) & (opCode & 0xff);
			break;
		case 0xd:
			mRegisters.V[0xf] = execDraw(mRegisters.V[x], mRegisters.V[y], opCode & 0xf);
			break;
		case 0xe:
			execKeyCheck(x, opCode);
			break;
		case 0xf:
			handleFxOps(opCode, x);
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::handle8xyOps(uint16_t opCode, uint8_t x, uint8_t y, uint8_t LSHB)
{
	auto& Vx = mRegisters.V[x];
	auto& Vy = mRegisters.V[y];
	auto& Vf = mRegisters.V[0xf];

	switch (LSHB) {
		case 0:
			Vx = Vy;
			break;
		case 1:
			Vx |= Vy;
			break;
		case 2:
			Vx &= Vy;
			break;
		case 3:
			Vx ^= Vy;
			break;
		case 4:
			Vx += Vy;
			// carry
			Vf = (Vx < Vy);
			break;
		case 5:
			// not borrow
			Vf = (Vx > Vy);
			Vx -= Vy;
			break;
		case 6:
			Vf = Vx & 1;
			Vx >>= 1;
			break;
		case 7:
			// not borrow
			Vf = (Vy > Vx);
			Vx = Vy - Vx;
			break;
		case 0xe:
			Vf = Vx >> 7;
			Vx <<= 1;
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::handleFxOps(uint16_t opCode, uint8_t x)
{
	switch (opCode & 0xff) {
		case 0x07:
			mRegisters.V[x] = mDelayTimer.getValue();
			break;
		case 0x0a:
			execGetKey(x);
			break;
		case 0x15:
			mDelayTimer.setValue(mRegisters.V[x]);
			break;
		case 0x18:
			mSoundTimer.setValue(mRegisters.V[x]);
			break;
		case 0x1e:
			mRegisters.I += mRegisters.V[x];
			mRegisters.V[0xf] = (mRegisters.I > 0xfff);
			break;
		case 0x29:
			mRegisters.I = mMemory.getCharacterSpriteAddress(mRegisters.V[x]);
			break;
		case 0x33:
			mMemory.write(static_cast<uint8_t>((mRegisters.V[x] / 100) % 10), mRegisters.I);
			mMemory.write(static_cast<uint8_t>((mRegisters.V[x] / 10) % 10), mRegisters.I + 1);
			mMemory.write(static_cast<uint8_t>(mRegisters.V[x] % 10), mRegisters.I + 2);
			break;
		case 0x55:
			execRegDump(x);
			break;
		case 0x65:
			execRegLoad(x);
			break;
		default:
			throw InvalidInstruction(opCode);
	}
}

void VM::execRegDump(uint8_t x)
{
	for (int i = 0; i <= x; ++i)
		mMemory.write(mRegisters.V[i], mRegisters.I + i);
}

void VM::execRegLoad(uint8_t x)
{
	for (int i = 0; i <= x; ++i)
		mRegisters.V[i] = mMemory.readUint8(mRegisters.I + i);
}

void VM::execReturn()
{
	mRegisters.pc = mStack.top();
	mStack.pop();
}

void VM::execGetKey(uint8_t x)
{
	Key key = mBackend.waitKey();

	if (key == Key::KEY_NONE)
		previousInst();
	else
		mRegisters.V[x] = key;
}

void VM::execKeyCheck(uint8_t x, uint16_t opCode)
{
	const bool pressed = mBackend.keyIsPressed(static_cast<Key>(mRegisters.V[x]));
	bool expected;

	switch (opCode & 0xff) {
		case 0x9e:
			expected = true;
			break;
		case 0xa1:
			expected = false;
			break;
		default:
			throw InvalidInstruction(opCode);
	}

	if (pressed == expected)
		nextInst();
}

bool VM::execDraw(uint8_t x, uint8_t y, uint8_t n)
{
	bool collision = false;

	for (int i = 0; i < n; ++i) {
		uint8_t sprite = mMemory.readUint8(mRegisters.I + i);
		/* const uint8_t y_ = (y + i) % Display::HEIGHT; */
		const uint8_t y_ = (y + i);

		if (y_ < Display::HEIGHT) {
			for (unsigned int j = 0; j < Display::SPRITE_WIDTH; ++j) {
				/* const uint8_t x_ = (x + j) % Display::WIDTH; */
				const uint8_t x_ = (x + j);

				if (x_ < Display::WIDTH) {
					const bool pixel = (sprite >> 7) & 1;

					if (pixel && mDisplay.flipPixel(x_, y_))
						collision = true;

					sprite <<= 1;
				}
			}
		}
	}

	mBackend.display(mDisplay);

	return collision;
}

/*
 * InvalidInstruction exception
 */
VM::InvalidInstruction::InvalidInstruction(uint16_t opCode) :
	std::runtime_error("Invalid OpCode: " + opCodeToHexStr(opCode))
{
}

std::string VM::InvalidInstruction::opCodeToHexStr(uint16_t opCode)
{
	std::stringstream stream;
	stream << "0x" << std::setfill('0') << std::setw(sizeof(opCode) * 2)
		<< std::hex << opCode;

	return stream.str();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010, 2011 Esrille 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 "Box.h"

#include <assert.h>

#include "CSSPropertyValueImp.h"
#include "CSSStyleDeclarationImp.h"
#include "StackingContext.h"
#include "ViewCSSImp.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

FormattingContext::FormattingContext() :
    lineBox(0),
    x(0.0f),
    leftover(0.0f),
    prevChar(0),
    marginLeft(0.0f),
    marginRight(0.0f),
    clearance(0.0f),
    usedMargin(0.0f),
    positiveMargin(0.0f),
    negativeMargin(0.0f),
    previousMargin(NAN),
    baseline(0.0f),
    lineHeight(0.0f),
    atLineHead(true)
{
}

float FormattingContext::getLeftoverForFloat(unsigned floatValue) const
{
    // cf. floats-rule3-outside-left-001 and floats-rule3-outside-right-001.
    switch (floatValue) {
    case CSSFloatValueImp::Left:
        if (!right.empty() && right.front()->edge < marginRight)
            return leftover + marginRight - right.front()->edge;
        break;
    case CSSFloatValueImp::Right:
        if (!left.empty() && left.front()->edge < marginLeft)
            return leftover + marginLeft - left.front()->edge;
        break;
    default:
        break;
    }
    return leftover;
}

float FormattingContext::getLeftEdge() const {
    if (left.empty())
        return 0.0f;
    return std::max(0.0f, left.back()->edge - marginLeft);
}

float FormattingContext::getRightEdge() const {
    if (right.empty())
        return 0.0f;
    return std::max(0.0f, right.front()->edge - marginRight);
}

float FormattingContext::getLeftRemainingHeight() const {
    if (left.empty())
        return 0.0f;
    return left.back()->remainingHeight;
}

float FormattingContext::getRightRemainingHeight() const {
    if (right.empty())
        return 0.0f;
    return right.front()->remainingHeight;
}

LineBox* FormattingContext::addLineBox(ViewCSSImp* view, BlockLevelBox* parentBox) {
    assert(!lineBox);
    assert(parentBox);
    baseline = lineHeight = 0.0f;
    lineBox = new(std::nothrow) LineBox(parentBox->getStyle());
    if (lineBox) {
        parentBox->appendChild(lineBox);

        // Set marginLeft and marginRight to the current values. Note these
        // margins do not contain the widths of the float boxes to be added
        // below.
        lineBox->marginLeft = getLeftEdge();
        lineBox->marginRight = getRightEdge();

        x = lineBox->marginLeft;
        leftover = parentBox->width - x - lineBox->marginRight;

        tryAddFloat(view);

        x = getLeftEdge();
        leftover = parentBox->width - x - getRightEdge();

        atLineHead = true;
    }
    return lineBox;
}

// if floatNodes is not empty, append float boxes as much as possible.
void FormattingContext::tryAddFloat(ViewCSSImp* view)
{
    while (!floatNodes.empty()) {
        BlockLevelBox* floatBox = view->getFloatBox(floatNodes.front());
        unsigned clear = floatBox->style->clear.getValue();
        if ((clear & CSSClearValueImp::Left) && !left.empty() ||
            (clear & CSSClearValueImp::Right) && !right.empty()) {
            break;
        }
        float w = floatBox->getEffectiveTotalWidth();
        if (leftover < w) {
            if (left.empty() && right.empty() && !lineBox->hasChildBoxes()) {
                addFloat(floatBox, w);
                floatNodes.pop_front();
            }
            break;
        }
        addFloat(floatBox, w);
        floatNodes.pop_front();
    }
}

float FormattingContext::adjustRemainingHeight(float h)
{
    float consumed = 0.0f;
    for (auto i = left.begin(); i != left.end();) {
        consumed = std::max(consumed, std::min(h, (*i)->remainingHeight));
        if (((*i)->remainingHeight -= h) <= 0.0f)
            i = left.erase(i);
        else
            ++i;    // consumed = h;
    }
    for (auto i = right.begin(); i != right.end();) {
        consumed = std::max(consumed, std::min(h, (*i)->remainingHeight));
        if (((*i)->remainingHeight -= h) <= 0.0f)
            i = right.erase(i);
        else
            ++i;
    }
    return consumed;
}

float FormattingContext::useMargin()
{
    float consumed = 0.0f;
    float m = getMargin();
    if (usedMargin < m) {
        consumed = adjustRemainingHeight(m - usedMargin);
        usedMargin = m;
    }
    return consumed;
}

void FormattingContext::updateRemainingHeight(float h)
{
    h += getMargin() - usedMargin;
    clearMargin();
    adjustRemainingHeight(h);
}

float FormattingContext::shiftDown(float width)
{
    float h = 0.0f;
    float w = 0.0f;
    do {
        float lh = getLeftRemainingHeight();
        float rh = getRightRemainingHeight();
        if (0.0f < lh && (lh < rh || rh <= 0.0f)) {
            // Shift down to left
            w = left.back()->getEffectiveTotalWidth();
            x -= w;
            leftover += w;
            if (left.size() == 1) {
                leftover += x;
                x = 0.0f;
            }
            h += lh;
        } else if (0.0f < rh && (rh < lh || lh <= 0.0f)) {
            // Shift down to right
            w = right.front()->getEffectiveTotalWidth();
            leftover += w;
            if (right.size() == 1)
                leftover = width - x;
            h += rh;
        } else if (0.0f < lh) {
            // Shift down to both
            float l = left.back()->getEffectiveTotalWidth();
            w = l + right.front()->getEffectiveTotalWidth();
            x -= l;
            leftover += w;
            if (left.size() == 1) {
                leftover += x;
                x = 0.0f;
            }
            if (right.size() == 1)
                leftover = width - x;
            h += lh;
        } else
            break;
    } while (w == 0.0f);
    return h;
}

// If there's a float, shiftDownLineBox() will expand leftover by extending
// marginTop in lineBox down to the bottom of the nearest float box.
bool FormattingContext::shiftDownLineBox(ViewCSSImp* view)
{
    assert(lineBox);
    if (float h = shiftDown(lineBox->getParentBox()->width)) {
        updateRemainingHeight(h);
        if (lineBox->hasClearance())
            lineBox->clearance += h;
        else
            lineBox->clearance = h;
        clearance += h;
        // Note updateRemainingHeight() could remove more than one floating box from this
        // context, and thus x and leftover have to be recalculated.
        lineBox->marginLeft = getLeftEdge();
        lineBox->marginRight = getRightEdge();
        x = lineBox->marginLeft;
        leftover = lineBox->getParentBox()->width - x - lineBox->marginRight;

        // If there are floating boxes in floatNodes, try adding those first;
        // cf. c414-flt-fit-001.
        tryAddFloat(view);
        x = getLeftEdge();
        leftover = lineBox->getParentBox()->width - x - getRightEdge();
        return true;
    }
    return false;  // no floats
}

bool FormattingContext::hasNewFloats() const
{
    if (!left.empty()) {
        BlockLevelBox* box = left.back();
        if (!box->inserted)
            return true;
    }
    if (!right.empty()) {
        BlockLevelBox* box = right.front();
        if (!box->inserted)
            return true;
    }
    return false;
}

void FormattingContext::appendInlineBox(InlineLevelBox* inlineBox, CSSStyleDeclarationImp* activeStyle)
{
    assert(lineBox);
    baseline = lineBox->baseline;
    lineHeight = lineBox->height;

    assert(activeStyle);
    float offset;
    if (activeStyle->display.isInlineLevel())
        offset = activeStyle->verticalAlign.getOffset(lineBox, inlineBox);
    else {
        float leading = inlineBox->getLeading() / 2.0f;
        offset = baseline - (leading + inlineBox->getBaseline());
    }
    if (offset < 0.0f) {
        lineBox->baseline -= offset;
        offset = 0.0f;
    }

    if (0.0f < inlineBox->height)
        lineBox->height = std::max(lineBox->height, offset + inlineBox->height);
    lineBox->height = std::max(lineBox->height, activeStyle->lineHeight.getPx());
    lineBox->height = std::max(lineBox->height, lineBox->getStyle()->lineHeight.getPx());

    lineBox->width += inlineBox->getTotalWidth();

    lineBox->appendChild(inlineBox);
    if (activeStyle->isPositioned() && !inlineBox->isAnonymous())
        activeStyle->getStackingContext()->addBase(inlineBox);

    atLineHead = false;
}

// Complete the current lineBox by adding float boxes if any.
// Then update remainingHeight.
void FormattingContext::nextLine(ViewCSSImp* view, BlockLevelBox* parentBox)
{
    assert(lineBox);
    assert(lineBox == parentBox->lastChild);

    if (InlineLevelBox* inlineLevelBox = dynamic_cast<InlineLevelBox*>(lineBox->getLastChild())) {
        float w = inlineLevelBox->atEndOfLine();
        if (w < 0.0f) {
            if (inlineLevelBox->width <= 0.0f) {
                lineBox->baseline = baseline;
                lineBox->height = lineHeight;
            }
            lineBox->width += w;
            leftover -= w;
            tryAddFloat(view);
        }
    }

    for (auto i = left.rbegin(); i != left.rend(); ++i) {
        BlockLevelBox* floatBox = *i;
        if (!floatBox->inserted) {
            floatBox->inserted = true;
            lineBox->insertBefore(floatBox, lineBox->getFirstChild());
            floatList.push_back(floatBox);
        }
    }
    for (auto i = right.begin(); i != right.end(); ++i) {
        BlockLevelBox* floatBox = *i;
        if (!floatBox->inserted) {
            floatBox->inserted = true;
            // We would need a gap before the 1st right floating box to be added.
            if (!lineBox->rightBox)
                lineBox->rightBox = floatBox;
            lineBox->appendChild(*i);
            floatList.push_back(floatBox);
        }
    }
    float height = lineBox->getClearance() + lineBox->getTotalHeight();
    if (height != 0.0f)
        updateRemainingHeight(height);
    lineBox = 0;
    x = leftover = 0.0f;
}

void FormattingContext::addFloat(BlockLevelBox* floatBox, float totalWidth)
{
    if (floatBox->style->float_.getValue() == CSSFloatValueImp::Left) {
        if (left.empty())
            floatBox->edge = marginLeft + totalWidth;
        else
            floatBox->edge = left.back()->edge + totalWidth;
        left.push_back(floatBox);
        x += totalWidth;
    } else {
        if (right.empty())
            floatBox->edge = marginRight + totalWidth;
        else
            floatBox->edge = right.front()->edge + totalWidth;
        right.push_front(floatBox);
    }
    leftover -= totalWidth;
}

float FormattingContext::clear(unsigned value)
{
    if (!value)
        return 0.0f;
    float h = NAN;
    if (value & 1) {  // clear left
        for (auto i = left.begin(); i != left.end(); ++i) {
            float w = (*i)->getEffectiveTotalWidth();
            x -= w;
            leftover += w;
            if (isnan(h))
                h = (*i)->remainingHeight;
            else
                h = std::max(h, (*i)->remainingHeight);
        }
    }
    if (value & 2) {  // clear right
        for (auto i = right.begin(); i != right.end(); ++i) {
            float w = (*i)->getEffectiveTotalWidth();
            leftover += w;
            if (isnan(h))
                h = (*i)->remainingHeight;
            else
                h = std::max(h, (*i)->remainingHeight);
        }
    }
    if (isnan(h))
        h = 0.0f;
    else {
        // Note there could be a floating box whose remainingHeight is zero.
        adjustRemainingHeight(h);
        h += usedMargin;
        clearMargin();
    }
    assert(!(value & 1) || left.empty());
    assert(!(value & 2) || right.empty());
    return h;
}

float FormattingContext::collapseMargins(float margin)
{
    if (0.0f <= margin) {
        previousMargin = positiveMargin;
        positiveMargin = std::max(positiveMargin, margin);
    } else {
        previousMargin = negativeMargin;
        negativeMargin = std::min(negativeMargin, margin);
    }
    return positiveMargin + negativeMargin;
}

float FormattingContext::undoCollapseMargins()
{
    if (!isnan(previousMargin)) {
        if (0.0f <= previousMargin)
            positiveMargin = previousMargin;
        else
            negativeMargin = previousMargin;
        previousMargin = NAN;
    }
    return positiveMargin + negativeMargin;
}

float FormattingContext::fixMargin()
{
    updateRemainingHeight(0.0f);
}

// TODO: Remove this function.
void FormattingContext::adjustRemainingFloatingBoxes(float topBorderEdge)
{
    floatList.clear();
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(FormattingContext::nextLine) : Fix a bug.<commit_after>/*
 * Copyright 2010, 2011 Esrille 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 "Box.h"

#include <assert.h>

#include "CSSPropertyValueImp.h"
#include "CSSStyleDeclarationImp.h"
#include "StackingContext.h"
#include "ViewCSSImp.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

FormattingContext::FormattingContext() :
    lineBox(0),
    x(0.0f),
    leftover(0.0f),
    prevChar(0),
    marginLeft(0.0f),
    marginRight(0.0f),
    clearance(0.0f),
    usedMargin(0.0f),
    positiveMargin(0.0f),
    negativeMargin(0.0f),
    previousMargin(NAN),
    baseline(0.0f),
    lineHeight(0.0f),
    atLineHead(true)
{
}

float FormattingContext::getLeftoverForFloat(unsigned floatValue) const
{
    // cf. floats-rule3-outside-left-001 and floats-rule3-outside-right-001.
    switch (floatValue) {
    case CSSFloatValueImp::Left:
        if (!right.empty() && right.front()->edge < marginRight)
            return leftover + marginRight - right.front()->edge;
        break;
    case CSSFloatValueImp::Right:
        if (!left.empty() && left.front()->edge < marginLeft)
            return leftover + marginLeft - left.front()->edge;
        break;
    default:
        break;
    }
    return leftover;
}

float FormattingContext::getLeftEdge() const {
    if (left.empty())
        return 0.0f;
    return std::max(0.0f, left.back()->edge - marginLeft);
}

float FormattingContext::getRightEdge() const {
    if (right.empty())
        return 0.0f;
    return std::max(0.0f, right.front()->edge - marginRight);
}

float FormattingContext::getLeftRemainingHeight() const {
    if (left.empty())
        return 0.0f;
    return left.back()->remainingHeight;
}

float FormattingContext::getRightRemainingHeight() const {
    if (right.empty())
        return 0.0f;
    return right.front()->remainingHeight;
}

LineBox* FormattingContext::addLineBox(ViewCSSImp* view, BlockLevelBox* parentBox) {
    assert(!lineBox);
    assert(parentBox);
    baseline = lineHeight = 0.0f;
    lineBox = new(std::nothrow) LineBox(parentBox->getStyle());
    if (lineBox) {
        parentBox->appendChild(lineBox);

        // Set marginLeft and marginRight to the current values. Note these
        // margins do not contain the widths of the float boxes to be added
        // below.
        lineBox->marginLeft = getLeftEdge();
        lineBox->marginRight = getRightEdge();

        x = lineBox->marginLeft;
        leftover = parentBox->width - x - lineBox->marginRight;

        tryAddFloat(view);

        x = getLeftEdge();
        leftover = parentBox->width - x - getRightEdge();

        atLineHead = true;
    }
    return lineBox;
}

// if floatNodes is not empty, append float boxes as much as possible.
void FormattingContext::tryAddFloat(ViewCSSImp* view)
{
    while (!floatNodes.empty()) {
        BlockLevelBox* floatBox = view->getFloatBox(floatNodes.front());
        unsigned clear = floatBox->style->clear.getValue();
        if ((clear & CSSClearValueImp::Left) && !left.empty() ||
            (clear & CSSClearValueImp::Right) && !right.empty()) {
            break;
        }
        float w = floatBox->getEffectiveTotalWidth();
        if (leftover < w) {
            if (left.empty() && right.empty() && !lineBox->hasChildBoxes()) {
                addFloat(floatBox, w);
                floatNodes.pop_front();
            }
            break;
        }
        addFloat(floatBox, w);
        floatNodes.pop_front();
    }
}

float FormattingContext::adjustRemainingHeight(float h)
{
    float consumed = 0.0f;
    for (auto i = left.begin(); i != left.end();) {
        consumed = std::max(consumed, std::min(h, (*i)->remainingHeight));
        if (((*i)->remainingHeight -= h) <= 0.0f)
            i = left.erase(i);
        else
            ++i;    // consumed = h;
    }
    for (auto i = right.begin(); i != right.end();) {
        consumed = std::max(consumed, std::min(h, (*i)->remainingHeight));
        if (((*i)->remainingHeight -= h) <= 0.0f)
            i = right.erase(i);
        else
            ++i;
    }
    return consumed;
}

float FormattingContext::useMargin()
{
    float consumed = 0.0f;
    float m = getMargin();
    if (usedMargin < m) {
        consumed = adjustRemainingHeight(m - usedMargin);
        usedMargin = m;
    }
    return consumed;
}

void FormattingContext::updateRemainingHeight(float h)
{
    h += getMargin() - usedMargin;
    clearMargin();
    adjustRemainingHeight(h);
}

float FormattingContext::shiftDown(float width)
{
    float h = 0.0f;
    float w = 0.0f;
    do {
        float lh = getLeftRemainingHeight();
        float rh = getRightRemainingHeight();
        if (0.0f < lh && (lh < rh || rh <= 0.0f)) {
            // Shift down to left
            w = left.back()->getEffectiveTotalWidth();
            x -= w;
            leftover += w;
            if (left.size() == 1) {
                leftover += x;
                x = 0.0f;
            }
            h += lh;
        } else if (0.0f < rh && (rh < lh || lh <= 0.0f)) {
            // Shift down to right
            w = right.front()->getEffectiveTotalWidth();
            leftover += w;
            if (right.size() == 1)
                leftover = width - x;
            h += rh;
        } else if (0.0f < lh) {
            // Shift down to both
            float l = left.back()->getEffectiveTotalWidth();
            w = l + right.front()->getEffectiveTotalWidth();
            x -= l;
            leftover += w;
            if (left.size() == 1) {
                leftover += x;
                x = 0.0f;
            }
            if (right.size() == 1)
                leftover = width - x;
            h += lh;
        } else
            break;
    } while (w == 0.0f);
    return h;
}

// If there's a float, shiftDownLineBox() will expand leftover by extending
// marginTop in lineBox down to the bottom of the nearest float box.
bool FormattingContext::shiftDownLineBox(ViewCSSImp* view)
{
    assert(lineBox);
    if (float h = shiftDown(lineBox->getParentBox()->width)) {
        updateRemainingHeight(h);
        if (lineBox->hasClearance())
            lineBox->clearance += h;
        else
            lineBox->clearance = h;
        clearance += h;
        // Note updateRemainingHeight() could remove more than one floating box from this
        // context, and thus x and leftover have to be recalculated.
        lineBox->marginLeft = getLeftEdge();
        lineBox->marginRight = getRightEdge();
        x = lineBox->marginLeft;
        leftover = lineBox->getParentBox()->width - x - lineBox->marginRight;

        // If there are floating boxes in floatNodes, try adding those first;
        // cf. c414-flt-fit-001.
        tryAddFloat(view);
        x = getLeftEdge();
        leftover = lineBox->getParentBox()->width - x - getRightEdge();
        return true;
    }
    return false;  // no floats
}

bool FormattingContext::hasNewFloats() const
{
    if (!left.empty()) {
        BlockLevelBox* box = left.back();
        if (!box->inserted)
            return true;
    }
    if (!right.empty()) {
        BlockLevelBox* box = right.front();
        if (!box->inserted)
            return true;
    }
    return false;
}

void FormattingContext::appendInlineBox(InlineLevelBox* inlineBox, CSSStyleDeclarationImp* activeStyle)
{
    assert(lineBox);
    baseline = lineBox->baseline;
    lineHeight = lineBox->height;

    assert(activeStyle);
    float offset;
    if (activeStyle->display.isInlineLevel())
        offset = activeStyle->verticalAlign.getOffset(lineBox, inlineBox);
    else {
        float leading = inlineBox->getLeading() / 2.0f;
        offset = baseline - (leading + inlineBox->getBaseline());
    }
    if (offset < 0.0f) {
        lineBox->baseline -= offset;
        offset = 0.0f;
    }

    if (0.0f < inlineBox->height)
        lineBox->height = std::max(lineBox->height, offset + inlineBox->height);
    lineBox->height = std::max(lineBox->height, activeStyle->lineHeight.getPx());
    lineBox->height = std::max(lineBox->height, lineBox->getStyle()->lineHeight.getPx());

    lineBox->width += inlineBox->getTotalWidth();

    lineBox->appendChild(inlineBox);
    if (activeStyle->isPositioned() && !inlineBox->isAnonymous())
        activeStyle->getStackingContext()->addBase(inlineBox);

    atLineHead = false;
}

// Complete the current lineBox by adding float boxes if any.
// Then update remainingHeight.
void FormattingContext::nextLine(ViewCSSImp* view, BlockLevelBox* parentBox)
{
    assert(lineBox);
    assert(lineBox == parentBox->lastChild);

    if (InlineLevelBox* inlineLevelBox = dynamic_cast<InlineLevelBox*>(lineBox->getLastChild())) {
        float w = inlineLevelBox->atEndOfLine();
        if (w < 0.0f) {
            if (inlineLevelBox->width <= 0.0f) {
                lineBox->baseline = baseline;
                lineBox->height = lineHeight;
            }
            lineBox->width += w;
            leftover -= w;
            tryAddFloat(view);
        }
    }

    for (auto i = left.rbegin(); i != left.rend(); ++i) {
        BlockLevelBox* floatBox = *i;
        if (!floatBox->inserted) {
            floatBox->inserted = true;
            lineBox->insertBefore(floatBox, lineBox->getFirstChild());
            floatList.push_back(floatBox);
        }
    }
    for (auto i = right.begin(); i != right.end(); ++i) {
        BlockLevelBox* floatBox = *i;
        if (!floatBox->inserted) {
            floatBox->inserted = true;
            // We would need a gap before the 1st right floating box to be added.
            if (!lineBox->rightBox)
                lineBox->rightBox = floatBox;
            lineBox->appendChild(*i);
            floatList.push_back(floatBox);
        }
    }
    float height = lineBox->getClearance() + lineBox->getTotalHeight();
    if (height != 0.0f)
        updateRemainingHeight(height);
    lineBox = 0;
    x = leftover = 0.0f;
    atLineHead = true;
}

void FormattingContext::addFloat(BlockLevelBox* floatBox, float totalWidth)
{
    if (floatBox->style->float_.getValue() == CSSFloatValueImp::Left) {
        if (left.empty())
            floatBox->edge = marginLeft + totalWidth;
        else
            floatBox->edge = left.back()->edge + totalWidth;
        left.push_back(floatBox);
        x += totalWidth;
    } else {
        if (right.empty())
            floatBox->edge = marginRight + totalWidth;
        else
            floatBox->edge = right.front()->edge + totalWidth;
        right.push_front(floatBox);
    }
    leftover -= totalWidth;
}

float FormattingContext::clear(unsigned value)
{
    if (!value)
        return 0.0f;
    float h = NAN;
    if (value & 1) {  // clear left
        for (auto i = left.begin(); i != left.end(); ++i) {
            float w = (*i)->getEffectiveTotalWidth();
            x -= w;
            leftover += w;
            if (isnan(h))
                h = (*i)->remainingHeight;
            else
                h = std::max(h, (*i)->remainingHeight);
        }
    }
    if (value & 2) {  // clear right
        for (auto i = right.begin(); i != right.end(); ++i) {
            float w = (*i)->getEffectiveTotalWidth();
            leftover += w;
            if (isnan(h))
                h = (*i)->remainingHeight;
            else
                h = std::max(h, (*i)->remainingHeight);
        }
    }
    if (isnan(h))
        h = 0.0f;
    else {
        // Note there could be a floating box whose remainingHeight is zero.
        adjustRemainingHeight(h);
        h += usedMargin;
        clearMargin();
    }
    assert(!(value & 1) || left.empty());
    assert(!(value & 2) || right.empty());
    return h;
}

float FormattingContext::collapseMargins(float margin)
{
    if (0.0f <= margin) {
        previousMargin = positiveMargin;
        positiveMargin = std::max(positiveMargin, margin);
    } else {
        previousMargin = negativeMargin;
        negativeMargin = std::min(negativeMargin, margin);
    }
    return positiveMargin + negativeMargin;
}

float FormattingContext::undoCollapseMargins()
{
    if (!isnan(previousMargin)) {
        if (0.0f <= previousMargin)
            positiveMargin = previousMargin;
        else
            negativeMargin = previousMargin;
        previousMargin = NAN;
    }
    return positiveMargin + negativeMargin;
}

float FormattingContext::fixMargin()
{
    updateRemainingHeight(0.0f);
}

// TODO: Remove this function.
void FormattingContext::adjustRemainingFloatingBoxes(float topBorderEdge)
{
    floatList.clear();
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>