<commit_before>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*
* 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 "ODReader.h"
#include "ODMultiUPCEANReader.h"
#include "ODCode39Reader.h"
#include "ODCode93Reader.h"
#include "ODCode128Reader.h"
#include "ODITFReader.h"
#include "ODCodabarReader.h"
#include "ODRSS14Reader.h"
#include "ODRSSExpandedReader.h"
#include "Result.h"
#include "BitArray.h"
#include "BinaryBitmap.h"
#include "DecodeHints.h"

#include <algorithm>
#include <utility>

namespace ZXing {
namespace OneD {

Reader::Reader(const DecodeHints& hints) :
	_tryHarder(hints.tryHarder()),
	_tryRotate(hints.tryRotate())
{
	_readers.reserve(8);

	if (hints.hasNoFormat()) {
		_readers.emplace_back(new MultiUPCEANReader(hints));
		_readers.emplace_back(new Code39Reader(hints));
		_readers.emplace_back(new CodabarReader(hints));
		_readers.emplace_back(new Code93Reader());
		_readers.emplace_back(new Code128Reader(hints));
		_readers.emplace_back(new ITFReader(hints));
		_readers.emplace_back(new RSS14Reader());
		_readers.emplace_back(new RSSExpandedReader());
	}
	else {
		if (hints.hasFormat(BarcodeFormat::EAN_13) ||
			hints.hasFormat(BarcodeFormat::UPC_A) ||
			hints.hasFormat(BarcodeFormat::EAN_8) ||
			hints.hasFormat(BarcodeFormat::UPC_E)) {
			_readers.emplace_back(new MultiUPCEANReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODE_39)) {
			_readers.emplace_back(new Code39Reader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODE_93)) {
			_readers.emplace_back(new Code93Reader());
		}
		if (hints.hasFormat(BarcodeFormat::CODE_128)) {
			_readers.emplace_back(new Code128Reader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::ITF)) {
			_readers.emplace_back(new ITFReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODABAR)) {
			_readers.emplace_back(new CodabarReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::RSS_14)) {
			_readers.emplace_back(new RSS14Reader());
		}
		if (hints.hasFormat(BarcodeFormat::RSS_EXPANDED)) {
			_readers.emplace_back(new RSSExpandedReader());
		}
	}
}

Reader::~Reader() = default;

/**
* We're going to examine rows from the middle outward, searching alternately above and below the
* middle, and farther out each time. rowStep is the number of rows between each successive
* attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
* middle + rowStep, then middle - (2 * rowStep), etc.
* rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
* decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
* image if "trying harder".
*
* @param image The image to decode
* @param hints Any hints that were requested
* @return The contents of the decoded barcode
* @throws NotFoundException Any spontaneous errors which occur
*/
static Result
DoDecode(const std::vector<std::unique_ptr<RowReader>>& readers, const BinaryBitmap& image, bool tryHarder)
{
	std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());

	int width = image.width();
	int height = image.height();

	int middle = height >> 1;
	int rowStep = std::max(1, height >> (tryHarder ? 8 : 5));
	int maxLines = tryHarder ?
		height :	// Look at the whole image, not just the center
		15;			// 15 rows spaced 1/32 apart is roughly the middle half of the image

	BitArray row(width);
#ifdef ZX_USE_NEW_ROW_READERS
	PatternRow bars;
	bars.reserve(128); // e.g. EAN-13 has 96 bars
#endif
	for (int x = 0; x < maxLines; x++) {

		// Scanning from the middle out. Determine which row we're looking at next:
		int rowStepsAboveOrBelow = (x + 1) / 2;
		bool isAbove = (x & 0x01) == 0; // i.e. is x even?
		int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
		if (rowNumber < 0 || rowNumber >= height) {
			// Oops, if we run off the top or bottom, stop
			break;
		}

#ifdef ZX_USE_NEW_ROW_READERS
		image.getPatternRow(rowNumber, bars);
		bool hasBitArray = false;
#else
		// Estimate black point for this row and load it:
		if (!image.getBlackRow(rowNumber, row)) {
			continue;
		}
#endif

		// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
		// handle decoding upside down barcodes.
		// Note: the RSSExpanded decoder depends on seeing each line from both directions. This
		// 'surprising' and inconsistent. It also requires the decoderState to be shared between
		// normal and reversed scans, which makes no sense in general because it would mix partial
		// detetection data from two codes of the same type next to each other. TODO..
		// See also https://github.com/nu-book/zxing-cpp/issues/87
		for (bool upsideDown : {false, true}) {
			// trying again?
			if (upsideDown) {
				// reverse the row and continue
				row.reverse();
#ifdef ZX_USE_NEW_ROW_READERS
				std::reverse(bars.begin(), bars.end());
#endif
			}
			// Look for a barcode
			for (size_t r = 0; r < readers.size(); ++r) {
#ifdef ZX_USE_NEW_ROW_READERS
				Result result = readers[r]->decodePattern(rowNumber, bars, decodingState[r]);
				if (result.status() == DecodeStatus::_internal) {
					if (!std::exchange(hasBitArray, true)) {
						row.clearBits();
						bool set = false;
						int pos = 0;
						for(int w : bars) {
							if (set)
								for (int i = 0; i < w; ++i)
									row.set(pos++);
							else
								pos += w;
							set = !set;
						}
					}
					result = readers[r]->decodeRow(rowNumber, row, decodingState[r]);
				}
#else
				Result result = readers[r]->decodeRow(rowNumber, row, decodingState[r]);
#endif
				if (result.isValid()) {
					if (upsideDown) {
						// update position (flip horizontally).
						auto points = result.position();
						for (auto& p : points) {
							p = {width - p.x - 1, p.y};
						}
						result.setPosition(std::move(points));
					}
					return result;
				}
			}
		}
	}
	return Result(DecodeStatus::NotFound);
}

Result
Reader::decode(const BinaryBitmap& image) const
{
	Result result = DoDecode(_readers, image, _tryHarder);

	if (!result.isValid() && _tryRotate && image.canRotate()) {
		auto rotatedImage = image.rotated(270);
		result = DoDecode(_readers, *rotatedImage, _tryHarder);
		if (result.isValid()) {
			// Update position
			auto points = result.position();
			int height = rotatedImage->height();
			for (auto& p : points) {
				p = {height - p.y - 1, p.x};
			}
			result.setPosition(std::move(points));
		}
	}

	result.metadata().put(ResultMetadata::ORIENTATION, result.orientation());

	return result;
}

} // OneD
} // ZXing
<commit_msg>Minor readability improvements<commit_after>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*
* 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 "ODReader.h"
#include "ODMultiUPCEANReader.h"
#include "ODCode39Reader.h"
#include "ODCode93Reader.h"
#include "ODCode128Reader.h"
#include "ODITFReader.h"
#include "ODCodabarReader.h"
#include "ODRSS14Reader.h"
#include "ODRSSExpandedReader.h"
#include "Result.h"
#include "BitArray.h"
#include "BinaryBitmap.h"
#include "DecodeHints.h"

#include <algorithm>
#include <utility>

namespace ZXing {
namespace OneD {

Reader::Reader(const DecodeHints& hints) :
	_tryHarder(hints.tryHarder()),
	_tryRotate(hints.tryRotate())
{
	_readers.reserve(8);

	if (hints.hasNoFormat()) {
		_readers.emplace_back(new MultiUPCEANReader(hints));
		_readers.emplace_back(new Code39Reader(hints));
		_readers.emplace_back(new CodabarReader(hints));
		_readers.emplace_back(new Code93Reader());
		_readers.emplace_back(new Code128Reader(hints));
		_readers.emplace_back(new ITFReader(hints));
		_readers.emplace_back(new RSS14Reader());
		_readers.emplace_back(new RSSExpandedReader());
	}
	else {
		if (hints.hasFormat(BarcodeFormat::EAN_13) ||
			hints.hasFormat(BarcodeFormat::UPC_A) ||
			hints.hasFormat(BarcodeFormat::EAN_8) ||
			hints.hasFormat(BarcodeFormat::UPC_E)) {
			_readers.emplace_back(new MultiUPCEANReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODE_39)) {
			_readers.emplace_back(new Code39Reader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODE_93)) {
			_readers.emplace_back(new Code93Reader());
		}
		if (hints.hasFormat(BarcodeFormat::CODE_128)) {
			_readers.emplace_back(new Code128Reader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::ITF)) {
			_readers.emplace_back(new ITFReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::CODABAR)) {
			_readers.emplace_back(new CodabarReader(hints));
		}
		if (hints.hasFormat(BarcodeFormat::RSS_14)) {
			_readers.emplace_back(new RSS14Reader());
		}
		if (hints.hasFormat(BarcodeFormat::RSS_EXPANDED)) {
			_readers.emplace_back(new RSSExpandedReader());
		}
	}
}

Reader::~Reader() = default;

/**
* We're going to examine rows from the middle outward, searching alternately above and below the
* middle, and farther out each time. rowStep is the number of rows between each successive
* attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
* middle + rowStep, then middle - (2 * rowStep), etc.
* rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
* decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
* image if "trying harder".
*
* @param image The image to decode
* @param hints Any hints that were requested
* @return The contents of the decoded barcode
* @throws NotFoundException Any spontaneous errors which occur
*/
static Result
DoDecode(const std::vector<std::unique_ptr<RowReader>>& readers, const BinaryBitmap& image, bool tryHarder)
{
	std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());

	int width = image.width();
	int height = image.height();

	int middle = height / 2;
	int rowStep = std::max(1, height / (tryHarder ? 256 : 32));
	int maxLines = tryHarder ?
		height :	// Look at the whole image, not just the center
		15;			// 15 rows spaced 1/32 apart is roughly the middle half of the image

	BitArray row(width);
#ifdef ZX_USE_NEW_ROW_READERS
	PatternRow bars;
	bars.reserve(128); // e.g. EAN-13 has 96 bars
#endif
	for (int i = 0; i < maxLines; i++) {

		// Scanning from the middle out. Determine which row we're looking at next:
		int rowStepsAboveOrBelow = (i + 1) / 2;
		bool isAbove = (i & 0x01) == 0; // i.e. is x even?
		int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
		if (rowNumber < 0 || rowNumber >= height) {
			// Oops, if we run off the top or bottom, stop
			break;
		}

#ifdef ZX_USE_NEW_ROW_READERS
		image.getPatternRow(rowNumber, bars);
		bool hasBitArray = false;
#else
		// Estimate black point for this row and load it:
		if (!image.getBlackRow(rowNumber, row)) {
			continue;
		}
#endif

		// While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
		// handle decoding upside down barcodes.
		// Note: the RSSExpanded decoder depends on seeing each line from both directions. This
		// 'surprising' and inconsistent. It also requires the decoderState to be shared between
		// normal and reversed scans, which makes no sense in general because it would mix partial
		// detetection data from two codes of the same type next to each other. TODO..
		// See also https://github.com/nu-book/zxing-cpp/issues/87
		for (bool upsideDown : {false, true}) {
			// trying again?
			if (upsideDown) {
				// reverse the row and continue
				row.reverse();
#ifdef ZX_USE_NEW_ROW_READERS
				std::reverse(bars.begin(), bars.end());
#endif
			}
			// Look for a barcode
			for (size_t r = 0; r < readers.size(); ++r) {
#ifdef ZX_USE_NEW_ROW_READERS
				Result result = readers[r]->decodePattern(rowNumber, bars, decodingState[r]);
				if (result.status() == DecodeStatus::_internal) {
					if (!std::exchange(hasBitArray, true)) {
						row.clearBits();
						bool set = false;
						int pos = 0;
						for(int w : bars) {
							if (set)
								for (int i = 0; i < w; ++i)
									row.set(pos++);
							else
								pos += w;
							set = !set;
						}
					}
					result = readers[r]->decodeRow(rowNumber, row, decodingState[r]);
				}
#else
				Result result = readers[r]->decodeRow(rowNumber, row, decodingState[r]);
#endif
				if (result.isValid()) {
					if (upsideDown) {
						// update position (flip horizontally).
						auto points = result.position();
						for (auto& p : points) {
							p = {width - p.x - 1, p.y};
						}
						result.setPosition(std::move(points));
					}
					return result;
				}
			}
		}
	}
	return Result(DecodeStatus::NotFound);
}

Result
Reader::decode(const BinaryBitmap& image) const
{
	Result result = DoDecode(_readers, image, _tryHarder);

	if (!result.isValid() && _tryRotate && image.canRotate()) {
		auto rotatedImage = image.rotated(270);
		result = DoDecode(_readers, *rotatedImage, _tryHarder);
		if (result.isValid()) {
			// Update position
			auto points = result.position();
			int height = rotatedImage->height();
			for (auto& p : points) {
				p = {height - p.y - 1, p.x};
			}
			result.setPosition(std::move(points));
		}
	}

	result.metadata().put(ResultMetadata::ORIENTATION, result.orientation());

	return result;
}

} // OneD
} // ZXing
<|endoftext|>


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

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

#include "base/i18n/rtl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu_model.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/avatar_menu_item_gtk.h"
#include "chrome/browser/ui/gtk/browser_toolbar_gtk.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_source.h"
#include "grit/generated_resources.h"
#include "ui/base/gtk/gtk_hig_constants.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

// The minimum width in pixels of the bubble.
const int kBubbleMinWidth = 175;

// The number of pixels of padding on the left of the 'New Profile' link at the
// bottom of the bubble.
const int kNewProfileLinkLeftPadding = 40;

}  // namespace

AvatarMenuBubbleGtk::AvatarMenuBubbleGtk(Browser* browser,
                                         GtkWidget* anchor,
                                         BubbleGtk::ArrowLocationGtk arrow,
                                         const gfx::Rect* rect)
    : contents_(NULL),
      theme_service_(GtkThemeService::GetFrom(browser->profile())),
      new_profile_link_(NULL),
      minimum_width_(kBubbleMinWidth) {
  avatar_menu_model_.reset(new AvatarMenuModel(
      &g_browser_process->profile_manager()->GetProfileInfoCache(),
      this, browser));

  InitContents();

  OnAvatarMenuModelChanged(avatar_menu_model_.get());

  bubble_ = BubbleGtk::Show(anchor,
                            rect,
                            contents_,
                            arrow,
                            true,  // |match_system_theme|
                            true,  // |grab_input|
                            theme_service_,
                            this);  // |delegate|
  g_signal_connect(contents_, "destroy",
                   G_CALLBACK(&OnDestroyThunk), this);

  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                 content::Source<ThemeService>(theme_service_));
  theme_service_->InitThemesFor(this);
}

AvatarMenuBubbleGtk::~AvatarMenuBubbleGtk() {
  STLDeleteContainerPointers(items_.begin(), items_.end());
}

void AvatarMenuBubbleGtk::OnDestroy(GtkWidget* widget) {
  // We are self deleting, we have a destroy signal setup to catch when we
  // destroyed (via the BubbleGtk being destroyed), and delete ourself.
  delete this;
}

void AvatarMenuBubbleGtk::BubbleClosing(BubbleGtk* bubble,
                                        bool closed_by_escape) {
}

void AvatarMenuBubbleGtk::OnAvatarMenuModelChanged(
    AvatarMenuModel* avatar_menu_model) {
  STLDeleteContainerPointers(items_.begin(), items_.end());
  items_.clear();
  minimum_width_ = kBubbleMinWidth;

  InitContents();
}

void AvatarMenuBubbleGtk::OpenProfile(size_t profile_index) {
  avatar_menu_model_->SwitchToProfile(profile_index);
  bubble_->Close();
}

void AvatarMenuBubbleGtk::EditProfile(size_t profile_index) {
  avatar_menu_model_->EditProfile(profile_index);
  bubble_->Close();
}

void AvatarMenuBubbleGtk::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
  gtk_chrome_link_button_set_use_gtk_theme(
      GTK_CHROME_LINK_BUTTON(new_profile_link_),
      theme_service_->UsingNativeTheme());
}

void AvatarMenuBubbleGtk::OnSizeRequest(GtkWidget* widget,
                                        GtkRequisition* req) {
  // Always use the maximum width ever requested.
  if (req->width < minimum_width_)
    req->width = minimum_width_;
  else
    minimum_width_ = req->width;
}

void AvatarMenuBubbleGtk::OnNewProfileLinkClicked(GtkWidget* link) {
  avatar_menu_model_->AddNewProfile();
  bubble_->Close();
}

void AvatarMenuBubbleGtk::InitContents() {
  size_t profile_count = avatar_menu_model_->GetNumberOfItems();

  contents_ = gtk_vbox_new(FALSE, ui::kControlSpacing);
  gtk_container_set_border_width(GTK_CONTAINER(contents_),
                                 ui::kContentAreaBorder);
  g_signal_connect(contents_, "size-request",
                   G_CALLBACK(OnSizeRequestThunk), this);

  GtkWidget* items_vbox = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);

  for (size_t i = 0; i < profile_count; ++i) {
    AvatarMenuModel::Item menu_item = avatar_menu_model_->GetItemAt(i);
    AvatarMenuItemGtk* item = new AvatarMenuItemGtk(
        this, menu_item, i, theme_service_);

    items_.push_back(item);

    gtk_box_pack_start(GTK_BOX(items_vbox), item->widget(), TRUE, TRUE, 0);
    gtk_widget_set_can_focus(item->widget(), TRUE);
    if (menu_item.active)
      gtk_container_set_focus_child(GTK_CONTAINER(items_vbox), item->widget());
  }

  gtk_box_pack_start(GTK_BOX(contents_), items_vbox, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(contents_), gtk_hseparator_new(), TRUE, TRUE, 0);

  // The new profile link.
  new_profile_link_ = gtk_chrome_link_button_new(
      l10n_util::GetStringUTF8(IDS_PROFILES_CREATE_NEW_PROFILE_LINK).c_str());
  g_signal_connect(new_profile_link_, "clicked",
                   G_CALLBACK(OnNewProfileLinkClickedThunk), this);

  GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(link_align),
                            0, 0, kNewProfileLinkLeftPadding, 0);
  gtk_container_add(GTK_CONTAINER(link_align), new_profile_link_);

  gtk_box_pack_start(GTK_BOX(contents_), link_align, FALSE, FALSE, 0);
}
<commit_msg>GTK: Fix crash on avatar bubble close<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

#include "base/i18n/rtl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu_model.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/avatar_menu_item_gtk.h"
#include "chrome/browser/ui/gtk/browser_toolbar_gtk.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_source.h"
#include "grit/generated_resources.h"
#include "ui/base/gtk/gtk_hig_constants.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

// The minimum width in pixels of the bubble.
const int kBubbleMinWidth = 175;

// The number of pixels of padding on the left of the 'New Profile' link at the
// bottom of the bubble.
const int kNewProfileLinkLeftPadding = 40;

}  // namespace

AvatarMenuBubbleGtk::AvatarMenuBubbleGtk(Browser* browser,
                                         GtkWidget* anchor,
                                         BubbleGtk::ArrowLocationGtk arrow,
                                         const gfx::Rect* rect)
    : contents_(NULL),
      theme_service_(GtkThemeService::GetFrom(browser->profile())),
      new_profile_link_(NULL),
      minimum_width_(kBubbleMinWidth) {
  avatar_menu_model_.reset(new AvatarMenuModel(
      &g_browser_process->profile_manager()->GetProfileInfoCache(),
      this, browser));

  InitContents();

  OnAvatarMenuModelChanged(avatar_menu_model_.get());

  bubble_ = BubbleGtk::Show(anchor,
                            rect,
                            contents_,
                            arrow,
                            true,  // |match_system_theme|
                            true,  // |grab_input|
                            theme_service_,
                            this);  // |delegate|
  g_signal_connect(contents_, "destroy",
                   G_CALLBACK(&OnDestroyThunk), this);

  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                 content::Source<ThemeService>(theme_service_));
  theme_service_->InitThemesFor(this);
}

AvatarMenuBubbleGtk::~AvatarMenuBubbleGtk() {
  STLDeleteContainerPointers(items_.begin(), items_.end());
}

void AvatarMenuBubbleGtk::OnDestroy(GtkWidget* widget) {
  // We are self deleting, we have a destroy signal setup to catch when we
  // destroyed (via the BubbleGtk being destroyed), and delete ourself.
  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void AvatarMenuBubbleGtk::BubbleClosing(BubbleGtk* bubble,
                                        bool closed_by_escape) {
}

void AvatarMenuBubbleGtk::OnAvatarMenuModelChanged(
    AvatarMenuModel* avatar_menu_model) {
  STLDeleteContainerPointers(items_.begin(), items_.end());
  items_.clear();
  minimum_width_ = kBubbleMinWidth;

  InitContents();
}

void AvatarMenuBubbleGtk::OpenProfile(size_t profile_index) {
  avatar_menu_model_->SwitchToProfile(profile_index);
  bubble_->Close();
}

void AvatarMenuBubbleGtk::EditProfile(size_t profile_index) {
  avatar_menu_model_->EditProfile(profile_index);
  bubble_->Close();
}

void AvatarMenuBubbleGtk::Observe(int type,
                                  const content::NotificationSource& source,
                                  const content::NotificationDetails& details) {
  DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
  gtk_chrome_link_button_set_use_gtk_theme(
      GTK_CHROME_LINK_BUTTON(new_profile_link_),
      theme_service_->UsingNativeTheme());
}

void AvatarMenuBubbleGtk::OnSizeRequest(GtkWidget* widget,
                                        GtkRequisition* req) {
  // Always use the maximum width ever requested.
  if (req->width < minimum_width_)
    req->width = minimum_width_;
  else
    minimum_width_ = req->width;
}

void AvatarMenuBubbleGtk::OnNewProfileLinkClicked(GtkWidget* link) {
  avatar_menu_model_->AddNewProfile();
  bubble_->Close();
}

void AvatarMenuBubbleGtk::InitContents() {
  size_t profile_count = avatar_menu_model_->GetNumberOfItems();

  contents_ = gtk_vbox_new(FALSE, ui::kControlSpacing);
  gtk_container_set_border_width(GTK_CONTAINER(contents_),
                                 ui::kContentAreaBorder);
  g_signal_connect(contents_, "size-request",
                   G_CALLBACK(OnSizeRequestThunk), this);

  GtkWidget* items_vbox = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);

  for (size_t i = 0; i < profile_count; ++i) {
    AvatarMenuModel::Item menu_item = avatar_menu_model_->GetItemAt(i);
    AvatarMenuItemGtk* item = new AvatarMenuItemGtk(
        this, menu_item, i, theme_service_);

    items_.push_back(item);

    gtk_box_pack_start(GTK_BOX(items_vbox), item->widget(), TRUE, TRUE, 0);
    gtk_widget_set_can_focus(item->widget(), TRUE);
    if (menu_item.active)
      gtk_container_set_focus_child(GTK_CONTAINER(items_vbox), item->widget());
  }

  gtk_box_pack_start(GTK_BOX(contents_), items_vbox, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(contents_), gtk_hseparator_new(), TRUE, TRUE, 0);

  // The new profile link.
  new_profile_link_ = gtk_chrome_link_button_new(
      l10n_util::GetStringUTF8(IDS_PROFILES_CREATE_NEW_PROFILE_LINK).c_str());
  g_signal_connect(new_profile_link_, "clicked",
                   G_CALLBACK(OnNewProfileLinkClickedThunk), this);

  GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0);
  gtk_alignment_set_padding(GTK_ALIGNMENT(link_align),
                            0, 0, kNewProfileLinkLeftPadding, 0);
  gtk_container_add(GTK_CONTAINER(link_align), new_profile_link_);

  gtk_box_pack_start(GTK_BOX(contents_), link_align, FALSE, FALSE, 0);
}
<|endoftext|>


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

#include "chrome/renderer/media/audio_renderer_impl.h"
#include "chrome/renderer/media/data_source_impl.h"
#include "chrome/renderer/media/video_renderer_impl.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/webmediaplayer_delegate_impl.h"
#include "googleurl/src/gurl.h"

/////////////////////////////////////////////////////////////////////////////
// Task to be posted on main thread that fire WebMediaPlayer methods.

class NotifyWebMediaPlayerTask : public CancelableTask {
 public:
  NotifyWebMediaPlayerTask(webkit_glue::WebMediaPlayer* web_media_player,
                           WebMediaPlayerMethod method)
      : web_media_player_(web_media_player),
        method_(method) {}

  virtual void Run() {
    if (web_media_player_) {
      (web_media_player_->*(method_))();
    }
  }

  virtual void Cancel() {
    web_media_player_ = NULL;
  }

 private:
  webkit_glue::WebMediaPlayer* web_media_player_;
  WebMediaPlayerMethod method_;

  DISALLOW_COPY_AND_ASSIGN(NotifyWebMediaPlayerTask);
};

/////////////////////////////////////////////////////////////////////////////
// WebMediaPlayerDelegateImpl implementation

WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* view)
    : network_state_(webkit_glue::WebMediaPlayer::EMPTY),
      ready_state_(webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE),
      main_loop_(NULL),
      filter_factory_(new media::FilterFactoryCollection()),
      audio_renderer_(NULL),
      video_renderer_(NULL),
      data_source_(NULL),
      web_media_player_(NULL),
      view_(view),
      tasks_(kLastTaskIndex) {
  // TODO(hclam): Add filter factory for demuxer and decoders.
  filter_factory_->AddFactory(AudioRendererImpl::CreateFactory(this));
  filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(this));
  filter_factory_->AddFactory(DataSourceImpl::CreateFactory(this));
}

WebMediaPlayerDelegateImpl::~WebMediaPlayerDelegateImpl() {
  // Stop the pipeline in the first place so we won't receive any more method
  // calls from it.
  pipeline_.Stop();

  // Cancel all tasks posted on the main_loop_.
  CancelAllTasks();

  // After cancelling all tasks, we are sure there will be no calls to
  // web_media_player_, so we are safe to delete it.
  if (web_media_player_) {
    delete web_media_player_;
  }

  // Finally tell the main_loop_ we don't want to be notified of destruction
  // event.
  if (main_loop_) {
    main_loop_->RemoveDestructionObserver(this);
  }
}

void WebMediaPlayerDelegateImpl::Initialize(
    webkit_glue::WebMediaPlayer* media_player) {
  DCHECK(!web_media_player_);
  web_media_player_ = media_player;

  // Saves the current message loop.
  DCHECK(!main_loop_);
  main_loop_ = MessageLoop::current();

  // Also we want to be notified of main_loop_ destruction.
  main_loop_->AddDestructionObserver(this);
}

void WebMediaPlayerDelegateImpl::Load(const GURL& url) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // Initialize the pipeline
  pipeline_.Start(filter_factory_.get(), url.spec(),
      NewCallback(this, &WebMediaPlayerDelegateImpl::DidInitializePipeline));
}

void WebMediaPlayerDelegateImpl::CancelLoad() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Calls to render_view_ to stop resource load
}

void WebMediaPlayerDelegateImpl::Play() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): We should restore the previous playback rate rather than
  // having it at 1.0.
  pipeline_.SetPlaybackRate(1.0f);
}

void WebMediaPlayerDelegateImpl::Pause() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetPlaybackRate(0.0f);
}

void WebMediaPlayerDelegateImpl::Stop() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // We can fire Stop() multiple times.
  pipeline_.Stop();
}

void WebMediaPlayerDelegateImpl::Seek(float time) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.Seek(base::TimeDelta::FromMilliseconds(static_cast<int64>(time)));
}

void WebMediaPlayerDelegateImpl::SetEndTime(float time) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add method call when it has been implemented.
  return;
}

void WebMediaPlayerDelegateImpl::SetPlaybackRate(float rate) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetPlaybackRate(rate);
}

void WebMediaPlayerDelegateImpl::SetVolume(float volume) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetVolume(volume);
}

void WebMediaPlayerDelegateImpl::SetVisible(bool visible) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add appropriate method call when pipeline has it implemented.
  return;
}

bool WebMediaPlayerDelegateImpl::IsTotalBytesKnown() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetTotalBytes() != 0;
}

bool WebMediaPlayerDelegateImpl::IsVideo() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return width != 0 && height != 0;
}

size_t WebMediaPlayerDelegateImpl::GetWidth() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return width;
}

size_t WebMediaPlayerDelegateImpl::GetHeight() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return height;
}

bool WebMediaPlayerDelegateImpl::IsPaused() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetPlaybackRate() == 0.0f;
}

bool WebMediaPlayerDelegateImpl::IsSeeking() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Add this method call if pipeline has it in the interface.
  return false;
}

float WebMediaPlayerDelegateImpl::GetDuration() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetDuration().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetCurrentTime() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetTime().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetPlayBackRate() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetPlaybackRate();
}

float WebMediaPlayerDelegateImpl::GetVolume() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetVolume();
}

int WebMediaPlayerDelegateImpl::GetDataRate() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Add this method call if pipeline has it in the interface.
  return 0;
}

float WebMediaPlayerDelegateImpl::GetMaxTimeBuffered() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetBufferedTime().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetMaxTimeSeekable() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add this method when pipeline has this method implemented.
  return 0.0f;
}

int64 WebMediaPlayerDelegateImpl::GetBytesLoaded() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetBufferedBytes();
}

int64 WebMediaPlayerDelegateImpl::GetTotalBytes() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetTotalBytes();
}

void WebMediaPlayerDelegateImpl::SetSize(const gfx::Size& size) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  if (video_renderer_) {
    // TODO(scherkus): Change API to use SetSize().
    video_renderer_->SetRect(gfx::Rect(0, 0, size.width(), size.height()));
  }
}

void WebMediaPlayerDelegateImpl::Paint(skia::PlatformCanvas *canvas,
                                       const gfx::Rect& rect) {
  if (video_renderer_) {
    video_renderer_->Paint(canvas, rect);
  }
}

void WebMediaPlayerDelegateImpl::WillDestroyCurrentMessageLoop() {
  // Instruct the renderers and data source to release all Renderer related
  // resources during destruction of render thread, because they won't have any
  // chance to release these resources on render thread by posting tasks on it.
  if (audio_renderer_) {
    audio_renderer_->ReleaseRendererResources();
    audio_renderer_ = NULL;
  }

  if (data_source_) {
    data_source_->ReleaseRendererResources();
    data_source_ = NULL;
  }

  // Stop the pipeline when the render thread is being destroyed so we won't be
  // posting any more messages onto it. And we just let this object and
  // associated WebMediaPlayer to leak.
  pipeline_.Stop();
}

void WebMediaPlayerDelegateImpl::DidInitializePipeline(bool successful) {
  if (successful) {
    // Since we have initialized the pipeline, we should be able to play it.
    // And we skip LOADED_METADATA state and starting with LOADED_FIRST_FRAME.
    ready_state_ = webkit_glue::WebMediaPlayer::CAN_PLAY;
    network_state_ = webkit_glue::WebMediaPlayer::LOADED_FIRST_FRAME;
  } else {
    // TODO(hclam): should use pipeline_.GetError() to determine the state
    // properly and reports error using MediaError.
    ready_state_ = webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE;
    network_state_ = webkit_glue::WebMediaPlayer::LOAD_FAILED;
  }

  PostTask(kNetworkStateTaskIndex,
           &webkit_glue::WebMediaPlayer::NotifyNetworkStateChange);
  PostTask(kReadyStateTaskIndex,
           &webkit_glue::WebMediaPlayer::NotifyReadyStateChange);
}

void WebMediaPlayerDelegateImpl::SetAudioRenderer(
    AudioRendererImpl* audio_renderer) {
  DCHECK(!audio_renderer_);
  audio_renderer_ = audio_renderer;
}

void WebMediaPlayerDelegateImpl::SetVideoRenderer(
    VideoRendererImpl* video_renderer) {
  DCHECK(!video_renderer_);
  video_renderer_ = video_renderer;
}

void WebMediaPlayerDelegateImpl::SetDataSource(
    DataSourceImpl* data_source) {
  data_source_ = data_source;
}

void WebMediaPlayerDelegateImpl::DidTask(CancelableTask* task) {
  AutoLock auto_lock(task_lock_);

  for (size_t i = 0; i < tasks_.size(); ++i) {
    if (tasks_[i] == task) {
      tasks_[i] = NULL;
      return;
    }
  }
  NOTREACHED();
}

void WebMediaPlayerDelegateImpl::CancelAllTasks() {
  AutoLock auto_lock(task_lock_);
  // Loop through the list of tasks and cancel tasks that are still alive.
  for (size_t i = 0; i < tasks_.size(); ++i) {
    if (tasks_[i])
      tasks_[i]->Cancel();
  }
}

void WebMediaPlayerDelegateImpl::PostTask(int index,
                                          WebMediaPlayerMethod method) {
  DCHECK(main_loop_);

  AutoLock auto_lock(task_lock_);
  if(!tasks_[index]) {
    CancelableTask* task = new NotifyWebMediaPlayerTask(web_media_player_,
                                                        method);
    tasks_[index] = task;
    main_loop_->PostTask(FROM_HERE, task);
  }
}

void WebMediaPlayerDelegateImpl::PostRepaintTask() {
  PostTask(kRepaintTaskIndex, &webkit_glue::WebMediaPlayer::Repaint);
}
<commit_msg>Fix a bug in WebMediaPlayerDelegateImpl that stalls video playback NotifyWebMediaPlayerTask is not calling WebMediaPlayerDelegateImpl::DidTask so new tasks are never scheduled. Also Changed NotifyWebMediaPlayerTask a bit so it can call DidTask.<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.  Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "chrome/renderer/media/audio_renderer_impl.h"
#include "chrome/renderer/media/data_source_impl.h"
#include "chrome/renderer/media/video_renderer_impl.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/webmediaplayer_delegate_impl.h"
#include "googleurl/src/gurl.h"

/////////////////////////////////////////////////////////////////////////////
// Task to be posted on main thread that fire WebMediaPlayer methods.

class NotifyWebMediaPlayerTask : public CancelableTask {
 public:
  NotifyWebMediaPlayerTask(WebMediaPlayerDelegateImpl* delegate,
                           WebMediaPlayerMethod method)
      : delegate_(delegate),
        method_(method) {}

  virtual void Run() {
    if (delegate_) {
      (delegate_->web_media_player()->*(method_))();
      delegate_->DidTask(this);
    }
  }

  virtual void Cancel() {
    delegate_ = NULL;
  }

 private:
  WebMediaPlayerDelegateImpl* delegate_;
  WebMediaPlayerMethod method_;

  DISALLOW_COPY_AND_ASSIGN(NotifyWebMediaPlayerTask);
};

/////////////////////////////////////////////////////////////////////////////
// WebMediaPlayerDelegateImpl implementation

WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* view)
    : network_state_(webkit_glue::WebMediaPlayer::EMPTY),
      ready_state_(webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE),
      main_loop_(NULL),
      filter_factory_(new media::FilterFactoryCollection()),
      audio_renderer_(NULL),
      video_renderer_(NULL),
      data_source_(NULL),
      web_media_player_(NULL),
      view_(view),
      tasks_(kLastTaskIndex) {
  // TODO(hclam): Add filter factory for demuxer and decoders.
  filter_factory_->AddFactory(AudioRendererImpl::CreateFactory(this));
  filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(this));
  filter_factory_->AddFactory(DataSourceImpl::CreateFactory(this));
}

WebMediaPlayerDelegateImpl::~WebMediaPlayerDelegateImpl() {
  // Stop the pipeline in the first place so we won't receive any more method
  // calls from it.
  pipeline_.Stop();

  // Cancel all tasks posted on the main_loop_.
  CancelAllTasks();

  // After cancelling all tasks, we are sure there will be no calls to
  // web_media_player_, so we are safe to delete it.
  if (web_media_player_) {
    delete web_media_player_;
  }

  // Finally tell the main_loop_ we don't want to be notified of destruction
  // event.
  if (main_loop_) {
    main_loop_->RemoveDestructionObserver(this);
  }
}

void WebMediaPlayerDelegateImpl::Initialize(
    webkit_glue::WebMediaPlayer* media_player) {
  DCHECK(!web_media_player_);
  web_media_player_ = media_player;

  // Saves the current message loop.
  DCHECK(!main_loop_);
  main_loop_ = MessageLoop::current();

  // Also we want to be notified of main_loop_ destruction.
  main_loop_->AddDestructionObserver(this);
}

void WebMediaPlayerDelegateImpl::Load(const GURL& url) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // Initialize the pipeline
  pipeline_.Start(filter_factory_.get(), url.spec(),
      NewCallback(this, &WebMediaPlayerDelegateImpl::DidInitializePipeline));
}

void WebMediaPlayerDelegateImpl::CancelLoad() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Calls to render_view_ to stop resource load
}

void WebMediaPlayerDelegateImpl::Play() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): We should restore the previous playback rate rather than
  // having it at 1.0.
  pipeline_.SetPlaybackRate(1.0f);
}

void WebMediaPlayerDelegateImpl::Pause() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetPlaybackRate(0.0f);
}

void WebMediaPlayerDelegateImpl::Stop() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // We can fire Stop() multiple times.
  pipeline_.Stop();
}

void WebMediaPlayerDelegateImpl::Seek(float time) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.Seek(base::TimeDelta::FromMilliseconds(static_cast<int64>(time)));
}

void WebMediaPlayerDelegateImpl::SetEndTime(float time) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add method call when it has been implemented.
  return;
}

void WebMediaPlayerDelegateImpl::SetPlaybackRate(float rate) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetPlaybackRate(rate);
}

void WebMediaPlayerDelegateImpl::SetVolume(float volume) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  pipeline_.SetVolume(volume);
}

void WebMediaPlayerDelegateImpl::SetVisible(bool visible) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add appropriate method call when pipeline has it implemented.
  return;
}

bool WebMediaPlayerDelegateImpl::IsTotalBytesKnown() {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetTotalBytes() != 0;
}

bool WebMediaPlayerDelegateImpl::IsVideo() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return width != 0 && height != 0;
}

size_t WebMediaPlayerDelegateImpl::GetWidth() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return width;
}

size_t WebMediaPlayerDelegateImpl::GetHeight() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  size_t width, height;
  pipeline_.GetVideoSize(&width, &height);
  return height;
}

bool WebMediaPlayerDelegateImpl::IsPaused() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetPlaybackRate() == 0.0f;
}

bool WebMediaPlayerDelegateImpl::IsSeeking() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Add this method call if pipeline has it in the interface.
  return false;
}

float WebMediaPlayerDelegateImpl::GetDuration() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetDuration().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetCurrentTime() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetTime().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetPlayBackRate() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetPlaybackRate();
}

float WebMediaPlayerDelegateImpl::GetVolume() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetVolume();
}

int WebMediaPlayerDelegateImpl::GetDataRate() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): Add this method call if pipeline has it in the interface.
  return 0;
}

float WebMediaPlayerDelegateImpl::GetMaxTimeBuffered() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return static_cast<float>(pipeline_.GetBufferedTime().InSecondsF());
}

float WebMediaPlayerDelegateImpl::GetMaxTimeSeekable() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  // TODO(hclam): add this method when pipeline has this method implemented.
  return 0.0f;
}

int64 WebMediaPlayerDelegateImpl::GetBytesLoaded() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetBufferedBytes();
}

int64 WebMediaPlayerDelegateImpl::GetTotalBytes() const {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  return pipeline_.GetTotalBytes();
}

void WebMediaPlayerDelegateImpl::SetSize(const gfx::Size& size) {
  DCHECK(main_loop_ && MessageLoop::current() == main_loop_);

  if (video_renderer_) {
    // TODO(scherkus): Change API to use SetSize().
    video_renderer_->SetRect(gfx::Rect(0, 0, size.width(), size.height()));
  }
}

void WebMediaPlayerDelegateImpl::Paint(skia::PlatformCanvas *canvas,
                                       const gfx::Rect& rect) {
  if (video_renderer_) {
    video_renderer_->Paint(canvas, rect);
  }
}

void WebMediaPlayerDelegateImpl::WillDestroyCurrentMessageLoop() {
  // Instruct the renderers and data source to release all Renderer related
  // resources during destruction of render thread, because they won't have any
  // chance to release these resources on render thread by posting tasks on it.
  if (audio_renderer_) {
    audio_renderer_->ReleaseRendererResources();
    audio_renderer_ = NULL;
  }

  if (data_source_) {
    data_source_->ReleaseRendererResources();
    data_source_ = NULL;
  }

  // Stop the pipeline when the render thread is being destroyed so we won't be
  // posting any more messages onto it. And we just let this object and
  // associated WebMediaPlayer to leak.
  pipeline_.Stop();
}

void WebMediaPlayerDelegateImpl::DidInitializePipeline(bool successful) {
  if (successful) {
    // Since we have initialized the pipeline, we should be able to play it.
    // And we skip LOADED_METADATA state and starting with LOADED_FIRST_FRAME.
    ready_state_ = webkit_glue::WebMediaPlayer::CAN_PLAY;
    network_state_ = webkit_glue::WebMediaPlayer::LOADED_FIRST_FRAME;
  } else {
    // TODO(hclam): should use pipeline_.GetError() to determine the state
    // properly and reports error using MediaError.
    ready_state_ = webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE;
    network_state_ = webkit_glue::WebMediaPlayer::LOAD_FAILED;
  }

  PostTask(kNetworkStateTaskIndex,
           &webkit_glue::WebMediaPlayer::NotifyNetworkStateChange);
  PostTask(kReadyStateTaskIndex,
           &webkit_glue::WebMediaPlayer::NotifyReadyStateChange);
}

void WebMediaPlayerDelegateImpl::SetAudioRenderer(
    AudioRendererImpl* audio_renderer) {
  DCHECK(!audio_renderer_);
  audio_renderer_ = audio_renderer;
}

void WebMediaPlayerDelegateImpl::SetVideoRenderer(
    VideoRendererImpl* video_renderer) {
  DCHECK(!video_renderer_);
  video_renderer_ = video_renderer;
}

void WebMediaPlayerDelegateImpl::SetDataSource(
    DataSourceImpl* data_source) {
  data_source_ = data_source;
}

void WebMediaPlayerDelegateImpl::DidTask(CancelableTask* task) {
  AutoLock auto_lock(task_lock_);

  for (size_t i = 0; i < tasks_.size(); ++i) {
    if (tasks_[i] == task) {
      tasks_[i] = NULL;
      return;
    }
  }
  NOTREACHED();
}

void WebMediaPlayerDelegateImpl::CancelAllTasks() {
  AutoLock auto_lock(task_lock_);
  // Loop through the list of tasks and cancel tasks that are still alive.
  for (size_t i = 0; i < tasks_.size(); ++i) {
    if (tasks_[i])
      tasks_[i]->Cancel();
  }
}

void WebMediaPlayerDelegateImpl::PostTask(int index,
                                          WebMediaPlayerMethod method) {
  DCHECK(main_loop_);

  AutoLock auto_lock(task_lock_);
  if(!tasks_[index]) {
    CancelableTask* task = new NotifyWebMediaPlayerTask(this, method);
    tasks_[index] = task;
    main_loop_->PostTask(FROM_HERE, task);
  }
}

void WebMediaPlayerDelegateImpl::PostRepaintTask() {
  PostTask(kRepaintTaskIndex, &webkit_glue::WebMediaPlayer::Repaint);
}
<|endoftext|>


<commit_before>//
// Created by Alan Chen on 3/29/17.
//

#include "client_http.hpp"
#include "server_http.hpp"

//Added for the default_resource example

#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>
#include "json.hpp"
#include <vector>
#include <algorithm>
#include <map>
#include <vector>
#include <time.h>

using namespace std;
using json = nlohmann::json;
typedef SimpleWeb::Client<SimpleWeb::HTTP> HttpClient;
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;

void pprint(string msg) {
    cout << "> " << msg << endl;
};

void pprint(string people, string msg) {
    cout << people << " > " << msg << endl;
};

struct LocalSession {
    string session_id = "failed";
    string scenario_id = "start";
    string story_id;
    string endpoint;
    HttpClient * connection;
    string game_server;
    string callback;
    LocalSession() {};

    void initialise(string callback_, string game_server_, string story_id_) {
        json j;
        story_id = story_id_;
        callback = callback_;
        game_server = game_server_;
        j["story_id"] = story_id;
        j["callback"] = callback;
        j["endpoint"] = "/json";
        callback = callback_;
        connection = new HttpClient(game_server);
        string response;
        try {
            response = (*this).request("/start", j.dump());
            auto r = json::parse(response);
            if (r["scenario"] == scenario_id) {
                session_id =  r["session_id"];
            } else {
                pprint("CStory", "Invalid response from the server:");
                cout << response << endl;
            }
        } catch (exception & e) {
            cout << "Error: " << e.what() << endl;
            cout << response << endl;
        }
    };

    string request(string path, string payload) {
        auto response = (*connection).request("POST", path, payload);
        try {
            stringstream ss;
            ss << response->content.rdbuf();
            string content=ss.str();
            return content;
        } catch (exception & e) {
            return response->status_code;
        }
    };

    void choose(json &choices) {
        int count = 1;
        vector<string> choices_vec;
        auto vec_it = choices_vec.begin();
        pprint("CStory", "What would you say?");
        for (json::iterator it = choices.begin(); it != choices.end(); ++it) {
            std::cout << count << " : " << it.value() << "\n"; // it.value is the text for the buttons
            choices_vec.insert(vec_it, it.key());
            vec_it = choices_vec.begin();
            ++count;
        }
        cout << "Reply: ";
        string choice;
        getline(cin, choice); // get the reply from user
        bool not_chosen = true;
        int choice_int;
        string choice_id;
        while (not_chosen) {
            try {
                choice_int = stoi(choice);
                if (choice_int > choices_vec.size() || choice_int < 1) {
                    throw(runtime_error("invalid choice_id"));
                }
                choice_id = choices_vec.at(choice_int);
                not_chosen = false;
            } catch (exception e) {
                cout << "Oops I can't hear you, can you repeat again?" << endl << "Reply: ";
                getline(cin, choice);
            };
        };
        pprint("You", choices[choice_id]);
        json j;
        j["session_id"] = session_id;
        j["choice"] = choice_id;
        choices = json();
        connection = new HttpClient(game_server);
        try {
            (*this).request("/json", j.dump());
        } catch (exception &e) {
            string str(e.what());
            pprint("CStory", "Error: " + str);
        }
    };

};

int main() {
    pprint("CStory", "Welcome to CStory Engine Demo Console Client.");
    pprint("CStory", "Which server do you want to connect? Default is localhost:8080");
    string game_server;
    cout << "Server: ";
    getline(cin, game_server);
    if (game_server.size() == 0) {
        game_server = "localhost:8080";
    }
    // start the client server so that the server can call
    HttpServer server;
    server.config.port=8081;

    pprint("CStory", "What story do you want to play? If you are not sure, default is silent_night.");
    string story_id;
    cout << "Enter a story id: ";
    getline(cin, story_id);
    if (story_id.size() == 0) {
        story_id = "silent_night";
    }

    json current_choices;

    LocalSession session = LocalSession();
    server.resource["^/json$"]["POST"]=[&session, &current_choices]
            (shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
        try {
            auto j = json::parse(request->content);
            string content;
            if (j["session_id"] != session.session_id) {
                throw(std::runtime_error("Invalid session_id."));
            }
            if (!j["choice"].get<bool>()) {
                pprint("Taylor", j["content"].get<string>()); // show message to the console
            } else { // this is a choice
                current_choices = j["choices"];
            }
            session.scenario_id = j["scenario_id"].get<string>();

            *response << "HTTP/1.1 200 OK\r\n"
                      << "Content-Type: application/json\r\n"
                      << "Content-Length: " << content.length() << "\r\n\r\n"
                      << content;
        }
        catch(exception& e) {
            json j;
            j["session_id"] = session.session_id;
            j["error"] = e.what();
            string err = j.dump();
            *response << "HTTP/1.1 400 Bad Request\r\n"
                      << "Content-Type: application/json\r\n"
                      << "Content-Length: " << err.size() << "\r\n\r\n" << err;
        }
    };

    thread server_thread([&server](){
        //Start server
        server.start();
    });

    // request for a session
    session.initialise("localhost:8081", game_server, story_id);
    if (session.session_id == "failed") {
        pprint("CStory", "Fatal error: cannot establish connection with the server.");
        return 1;
    }

    cout << "[Incoming Connection]" << endl;

    while(true) {
        if (!current_choices.empty()) {
            session.choose(current_choices);
        } else {
            boost::this_thread::sleep(boost::posix_time::milliseconds(10));
        }
    }

    server_thread.join();
    return 0;
}
<commit_msg>acknowledgement for delay event in console client<commit_after>//
// Created by Alan Chen on 3/29/17.
//

#include "client_http.hpp"
#include "server_http.hpp"

//Added for the default_resource example

#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>
#include "json.hpp"
#include <vector>
#include <algorithm>
#include <map>
#include <vector>
#include <time.h>

using namespace std;
using json = nlohmann::json;
typedef SimpleWeb::Client<SimpleWeb::HTTP> HttpClient;
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;

void pprint(string msg) {
    cout << "> " << msg << endl;
};

void pprint(string people, string msg) {
    cout << people << " > " << msg << endl;
};

struct LocalSession {
    string session_id = "failed";
    string scenario_id = "start";
    string story_id;
    string endpoint;
    HttpClient * connection;
    string game_server;
    string callback;
    LocalSession() {};

    void initialise(string callback_, string game_server_, string story_id_) {
        json j;
        story_id = story_id_;
        callback = callback_;
        game_server = game_server_;
        j["story_id"] = story_id;
        j["callback"] = callback;
        j["endpoint"] = "/json";
        callback = callback_;
        connection = new HttpClient(game_server);
        string response;
        try {
            response = (*this).request("/start", j.dump());
            auto r = json::parse(response);
            if (r["scenario"] == scenario_id) {
                session_id =  r["session_id"];
            } else {
                pprint("CStory", "Invalid response from the server:");
                cout << response << endl;
            }
        } catch (exception & e) {
            cout << "Error: " << e.what() << endl;
            cout << response << endl;
        }
    };

    string request(string path, string payload) {
        auto response = (*connection).request("POST", path, payload);
        try {
            stringstream ss;
            ss << response->content.rdbuf();
            string content=ss.str();
            return content;
        } catch (exception & e) {
            return response->status_code;
        }
    };

    void choose(json &choices) {
        int count = 1;
        vector<string> choices_vec;
        pprint("CStory", "What would you say?");
        for (json::iterator it = choices.begin(); it != choices.end(); ++it) {
            std::cout << count << " : " << it.value() << "\n"; // it.value is the text for the buttons
            choices_vec.push_back(it.key());
            ++count;
        }
        cout << "Reply: ";
        string choice;
        getline(cin, choice); // get the reply from user
        bool not_chosen = true;
        int choice_int;
        string choice_id;
        while (not_chosen) {
            try {
                choice_int = stoi(choice);
                if (choice_int > choices_vec.size() || choice_int < 1) {
                    throw(runtime_error("invalid choice_id"));
                }
                choice_id = choices_vec.at(choice_int - 1);
                not_chosen = false;
            } catch (exception e) {
                cout << "Oops I can't hear you, can you repeat again?" << endl << "Reply: ";
                getline(cin, choice);
            };
        };
        pprint("You", choices[choice_id]);
        json j;
        j["session_id"] = session_id;
        j["choice"] = choice_id;
        choices = json();
        connection = new HttpClient(game_server);
        try {
            (*this).request("/json", j.dump());
        } catch (exception &e) {
            string str(e.what());
            pprint("CStory", "Error: " + str);
        }
    };

};

int main() {
    pprint("CStory", "Welcome to CStory Engine Demo Console Client.");
    pprint("CStory", "Which server do you want to connect? Default is localhost:8080");
    string game_server;
    cout << "Server: ";
    getline(cin, game_server);
    if (game_server.size() == 0) {
        game_server = "localhost:8080";
    }
    // start the client server so that the server can call
    HttpServer server;
    server.config.port=8081;

    pprint("CStory", "What story do you want to play? If you are not sure, default is silent_night.");
    string story_id;
    cout << "Enter a story id: ";
    getline(cin, story_id);
    if (story_id.size() == 0) {
        story_id = "silent_night";
    }

    json current_choices;

    LocalSession session = LocalSession();
    server.resource["^/json$"]["POST"]=[&session, &current_choices]
            (shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
        try {
            auto j = json::parse(request->content);
            string content;
            if (j["session_id"] != session.session_id) {
                throw(std::runtime_error("Invalid session_id."));
            }
            if (!j["choice"].get<bool>()) {
                pprint("Taylor", j["content"].get<string>()); // show message to the console
            } else if (!j["delay"].is_null()) {
                pprint("CStory", "Taylor will get back to you in a while.");
            } else { // this is a choice
                current_choices = j["choices"];
            }
            session.scenario_id = j["scenario_id"].get<string>();

            *response << "HTTP/1.1 200 OK\r\n"
                      << "Content-Type: application/json\r\n"
                      << "Content-Length: " << content.length() << "\r\n\r\n"
                      << content;
        }
        catch(exception& e) {
            json j;
            j["session_id"] = session.session_id;
            j["error"] = e.what();
            string err = j.dump();
            *response << "HTTP/1.1 400 Bad Request\r\n"
                      << "Content-Type: application/json\r\n"
                      << "Content-Length: " << err.size() << "\r\n\r\n" << err;
        }
    };

    thread server_thread([&server](){
        //Start server
        server.start();
    });

    // request for a session
    session.initialise("localhost:8081", game_server, story_id);
    if (session.session_id == "failed") {
        pprint("CStory", "Fatal error: cannot establish connection with the server.");
        return 1;
    }

    cout << "[Incoming Connection]" << endl;

    while(true) {
        if (!current_choices.empty()) {
            session.choose(current_choices);
        } else {
            boost::this_thread::sleep(boost::posix_time::milliseconds(10));
        }
    }

    server_thread.join();
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
//    https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

#include <stdio.h>

#include <cstring>
#include <vector>

#include "libspirv/libspirv.h"

static void print_usage(char* argv0) {
  printf(
      R"(%s - Disassemble a binary SPIR-V module

Usage: %s [options] [<filename>]

Options:

  -h, --help      Print this help.

  -o <filename>   Set the output filename.
                  Otherwise output goes to standard output.

  --no-color      Don't print in color.
                  The default when output goes to a file.

  --no-indent     Don't indent instructions.
)",
      argv0, argv0);
}

int main(int argc, char** argv) {
  if (2 > argc) {
    print_usage(argv[0]);
    return 1;
  }

  const char* inFile = nullptr;
  const char* outFile = nullptr;

  bool allow_color = false;
#ifdef SPIRV_COLOR_TERMINAL
  allow_color = true;
#endif
  bool allow_indent = true;

  for (int argi = 1; argi < argc; ++argi) {
    if ('-' == argv[argi][0]) {
      switch (argv[argi][1]) {
        case 'h':
          print_usage(argv[0]);
          return 0;
        case 'o': {
          if (!outFile && argi + 1 < argc) {
            outFile = argv[++argi];
          } else {
            print_usage(argv[0]);
            return 1;
          }
        } break;
        case '-': {
          // Long options
          if (0 == strcmp(argv[argi], "--no-color")) allow_color = false;
          if (0 == strcmp(argv[argi], "--no-indent")) allow_indent = false;
          if (0 == strcmp(argv[argi], "--help")) {
            print_usage(argv[0]);
            return 0;
          }
        } break;
        default:
          print_usage(argv[0]);
          return 1;
      }
    } else {
      if (!inFile) {
        inFile = argv[argi];
      } else {
        print_usage(argv[0]);
        return 1;
      }
    }
  }

  uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;

  if (allow_indent)
    options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;

  if (!outFile) {
    // Print to standard output.
    options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
    if (allow_color) {
      options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
    }
  }

  if (!inFile) {
    fprintf(stderr, "error: input file is empty.\n");
    return 1;
  }

  std::vector<uint32_t> contents;
  if (FILE* fp = fopen(inFile, "rb")) {
    uint32_t buf[1024];
    while (size_t len = fread(buf, sizeof(uint32_t), 1024, fp)) {
      contents.insert(contents.end(), buf, buf + len);
    }
    fclose(fp);
  } else {
    fprintf(stderr, "error: file does not exist '%s'\n", inFile);
    return 1;
  }

  // If printing to standard output, then spvBinaryToText should
  // do the printing.  In particular, colour printing on Windows is
  // controlled by modifying console objects synchronously while
  // outputting to the stream rather than by injecting escape codes
  // into the output stream.
  // If the printing option is off, then save the text in memory, so
  // it can be emitted later in this function.
  const bool print_to_stdout =
      spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
  spv_text text;
  spv_text* textOrNull = print_to_stdout ? nullptr : &text;
  spv_diagnostic diagnostic = nullptr;
  spv_context context = spvContextCreate();
  spv_result_t error =
      spvBinaryToText(context, contents.data(), contents.size(), options,
                      textOrNull, &diagnostic);
  spvContextDestroy(context);
  if (error) {
    spvDiagnosticPrint(diagnostic);
    spvDiagnosticDestroy(diagnostic);
    return error;
  }

  // Output the result.
  if (!print_to_stdout) {
    if (FILE* fp = fopen(outFile, "w")) {
      size_t written =
          fwrite(text->str, sizeof(char), (size_t)text->length, fp);
      if (text->length != written) {
        spvTextDestroy(text);
        fprintf(stderr, "error: could not write to file '%s'\n", outFile);
        return 1;
      }
    } else {
      spvTextDestroy(text);
      fprintf(stderr, "error: could not open file '%s'\n", outFile);
      return 1;
    }
  }

  return 0;
}
<commit_msg>Disassembler can read the binary from stdin.<commit_after>// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
//    https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

#include <cstdio>
#include <cstring>
#include <string>
#include <vector>

#include "libspirv/libspirv.h"

static void print_usage(char* argv0) {
  printf(
      R"(%s - Disassemble a SPIR-V binary module

Usage: %s [options] [<filename>]

The SPIR-V binary is read from <filename>. If no file is specified,
or if the filename is "-", then the binary is read from standard input.

Options:

  -h, --help      Print this help.

  -o <filename>   Set the output filename.
                  Output goes to standard output if this option is
                  not specified, or if the filename is "-".

  --no-color      Don't print in color.
                  The default when output goes to a file.

  --no-indent     Don't indent instructions.
)",
      argv0, argv0);
}

int main(int argc, char** argv) {
  const char* inFile = nullptr;
  const char* outFile = nullptr;

  bool allow_color = false;
#ifdef SPIRV_COLOR_TERMINAL
  allow_color = true;
#endif
  bool allow_indent = true;

  for (int argi = 1; argi < argc; ++argi) {
    if ('-' == argv[argi][0]) {
      switch (argv[argi][1]) {
        case 'h':
          print_usage(argv[0]);
          return 0;
        case 'o': {
          if (!outFile && argi + 1 < argc) {
            outFile = argv[++argi];
          } else {
            print_usage(argv[0]);
            return 1;
          }
        } break;
        case '-': {
          // Long options
          if (0 == strcmp(argv[argi], "--no-color")) allow_color = false;
          if (0 == strcmp(argv[argi], "--no-indent")) allow_indent = false;
          if (0 == strcmp(argv[argi], "--help")) {
            print_usage(argv[0]);
            return 0;
          }
        } break;
        case 0:
          // Setting a filename of "-" to indicate stdin.
          if (!inFile) {
            inFile = argv[argi];
          } else {
            fprintf(stderr, "error: More than one input file specified\n");
            return 1;
          }
          break;
        default:
          print_usage(argv[0]);
          return 1;
      }
    } else {
      if (!inFile) {
        inFile = argv[argi];
      } else {
        fprintf(stderr, "error: More than one input file specified\n");
        return 1;
      }
    }
  }

  uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;

  if (allow_indent)
    options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;

  if (!outFile || (0 == strcmp("-", outFile))) {
    // Print to standard output.
    options |= SPV_BINARY_TO_TEXT_OPTION_PRINT;
    if (allow_color) {
      options |= SPV_BINARY_TO_TEXT_OPTION_COLOR;
    }
  }

  // Read the input binary.
  std::vector<uint32_t> contents;
  {
    FILE* input = stdin;
    const bool use_file = inFile && strcmp("-", inFile);
    if (use_file) {
      input = fopen(inFile, "rb");
      if (!input) {
        auto msg =
            std::string("error: Can't open file ") + inFile + " for reading";
        perror(msg.c_str());
        return 1;
      }
    }
    uint32_t buf[1024];
    while (size_t len = fread(buf, sizeof(uint32_t), 1024, input)) {
      contents.insert(contents.end(), buf, buf + len);
    }
    if (use_file) fclose(input);
  }

  // If printing to standard output, then spvBinaryToText should
  // do the printing.  In particular, colour printing on Windows is
  // controlled by modifying console objects synchronously while
  // outputting to the stream rather than by injecting escape codes
  // into the output stream.
  // If the printing option is off, then save the text in memory, so
  // it can be emitted later in this function.
  const bool print_to_stdout =
      spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
  spv_text text;
  spv_text* textOrNull = print_to_stdout ? nullptr : &text;
  spv_diagnostic diagnostic = nullptr;
  spv_context context = spvContextCreate();
  spv_result_t error =
      spvBinaryToText(context, contents.data(), contents.size(), options,
                      textOrNull, &diagnostic);
  spvContextDestroy(context);
  if (error) {
    spvDiagnosticPrint(diagnostic);
    spvDiagnosticDestroy(diagnostic);
    return error;
  }

  // Output the result.
  if (!print_to_stdout) {
    if (FILE* fp = fopen(outFile, "w")) {
      size_t written =
          fwrite(text->str, sizeof(char), (size_t)text->length, fp);
      if (text->length != written) {
        spvTextDestroy(text);
        fprintf(stderr, "error: Could not write to file '%s'\n", outFile);
        return 1;
      }
    } else {
      spvTextDestroy(text);
      fprintf(stderr, "error: Could not open file '%s'\n", outFile);
      return 1;
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2014.  ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/

#include "uct_p2p_test.h"

class uct_flush_test : public uct_test {
public:
    static const uint64_t SEED1 = 0x1111111111111111lu;
    static const uint64_t SEED2 = 0x2222222222222222lu;
    static const uint64_t SEED3 = 0x3333333333333333lu;
    static const int      AM_ID = 1;

    typedef void (uct_flush_test::* flush_func_t)();

    struct test_req_t {
        uct_pending_req_t  uct;
        uct_completion_t   comp;
        mapped_buffer      *sendbuf;
        uct_flush_test     *test;
    };

    void init() {
        m_sender = uct_test::create_entity(0);
        m_entities.push_back(m_sender);

        m_receiver = uct_test::create_entity(0);
        m_entities.push_back(m_receiver);

        m_sender->connect(0, *m_receiver, 0);
    }

    static size_t pack_cb(void *dest, void *arg)
    {
        const mapped_buffer *sendbuf = (const mapped_buffer *)arg;
        memcpy(dest, sendbuf->ptr(), sendbuf->length());
        return sendbuf->length();
    }

    void blocking_put_bcopy(const mapped_buffer &sendbuf,
                            const mapped_buffer &recvbuf)
    {
        ssize_t status;
         for (;;) {
             status = uct_ep_put_bcopy(m_sender->ep(0), pack_cb, (void*)&sendbuf,
                                       recvbuf.addr(), recvbuf.rkey());
             if (status >= 0) {
                 return;
             } else if (status == UCS_ERR_NO_RESOURCE) {
                 progress();
                 continue;
             } else {
                 ASSERT_UCS_OK((ucs_status_t)status);
             }
         }
    }

    void blocking_am_bcopy(const mapped_buffer &sendbuf)
    {
         ssize_t status;
         for (;;) {
             status = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                      (void*)&sendbuf);
             if (status >= 0) {
                 return;
             } else if (status == UCS_ERR_NO_RESOURCE) {
                 progress();
                 continue;
             } else {
                 ASSERT_UCS_OK((ucs_status_t)status);
             }
         }
    }

    static ucs_status_t am_handler(void *arg, void *data, size_t length,
                                   void *desc)
    {
        const mapped_buffer *recvbuf = (const mapped_buffer *)arg;
        memcpy(recvbuf->ptr(), data, ucs_min(length, recvbuf->length()));
        return UCS_OK;
    }

    ucs_status_t am_send_pending(test_req_t *am_req)
    {
        ssize_t status;

        status = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                 (void*)am_req->sendbuf);
        if (status >= 0) {
            --am_req->comp.count;
            return UCS_OK;
        } else {
            return (ucs_status_t)status;
        }
    }

    static ucs_status_t am_progress(uct_pending_req_t *req)
    {
        test_req_t *am_req = ucs_container_of(req, test_req_t, uct);
        return am_req->test->am_send_pending(am_req);
    }

    static ucs_status_t flush_progress(uct_pending_req_t *req)
    {
        test_req_t *flush_req = ucs_container_of(req, test_req_t, uct);
        ucs_status_t status;

        status = uct_ep_flush(flush_req->test->m_sender->ep(0), 0,
                              &flush_req->comp);
        if (status == UCS_OK) {
            --flush_req->comp.count;
            return UCS_OK;
        } else if (status == UCS_INPROGRESS) {
            return UCS_OK;
        } else if (status == UCS_ERR_NO_RESOURCE) {
            return UCS_ERR_NO_RESOURCE;
        } else {
            UCS_TEST_ABORT("Error: " << ucs_status_string(status));
        }
    }

    virtual void test_flush_put_bcopy(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_PUT_SHORT);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);
        blocking_put_bcopy(sendbuf, recvbuf);
        (this->*flush)();
        recvbuf.pattern_check(SEED3);
    }

    virtual void test_flush_am_zcopy(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_AM_ZCOPY);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                                 UCT_AM_CB_FLAG_ASYNC);

        uct_completion_t zcomp;
        zcomp.count = 2;
        zcomp.func  = NULL;

        ucs_status_t status;
        do {
            status = uct_ep_am_zcopy(m_sender->ep(0), AM_ID, NULL, 0, sendbuf.ptr(),
                                     sendbuf.length(), sendbuf.memh(), &zcomp);
        } while (status == UCS_ERR_NO_RESOURCE);
        ASSERT_UCS_OK_OR_INPROGRESS(status);
        if (status == UCS_OK) {
            --zcomp.count;
        }

        (this->*flush)();

        EXPECT_EQ(1, zcomp.count); /* Zero copy op should be already completed
                                      since flush returned */

        m_sender->destroy_ep(0);

        short_progress_loop();

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

        recvbuf.pattern_check(SEED3);
    }

    virtual void test_flush_am_disconnect(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_AM_BCOPY);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                                 UCT_AM_CB_FLAG_ASYNC);
        blocking_am_bcopy(sendbuf);
        (this->*flush)();
        m_sender->destroy_ep(0);

        short_progress_loop();

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

        recvbuf.pattern_check(SEED3);
    }

    void flush_ep_no_comp() {
        ucs_status_t status;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, NULL);
        } while ((status == UCS_ERR_NO_RESOURCE) || (status == UCS_INPROGRESS));
        ASSERT_UCS_OK(status);
    }

    void flush_iface_no_comp() {
        ucs_status_t status;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, NULL);
        } while ((status == UCS_ERR_NO_RESOURCE) || (status == UCS_INPROGRESS));
        ASSERT_UCS_OK(status);
    }

    void flush_ep_nb() {
        uct_completion_t comp;
        ucs_status_t status;
        comp.count = 2;
        comp.func  = NULL;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, &comp);
        } while (status == UCS_ERR_NO_RESOURCE);
        ASSERT_UCS_OK_OR_INPROGRESS(status);
        if (status == UCS_OK) {
            return;
        }
        /* coverity[loop_condition] */
        while (comp.count != 1) {
            progress();
        }
    }

protected:
    entity *m_sender;
    entity *m_receiver;
};

UCS_TEST_P(uct_flush_test, put_bcopy_flush_ep_no_comp) {
    test_flush_put_bcopy(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, put_bcopy_flush_iface_no_comp) {
    test_flush_put_bcopy(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, put_bcopy_flush_ep_nb) {
    test_flush_put_bcopy(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_ep_no_comp) {
    test_flush_am_zcopy(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_iface_no_comp) {
    test_flush_am_zcopy(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_ep_nb) {
    test_flush_am_zcopy(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_flush_ep_no_comp) {
    test_flush_am_disconnect(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, am_flush_iface_no_comp) {
    test_flush_am_disconnect(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, am_flush_ep_nb) {
    test_flush_am_disconnect(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_pending_flush_nb) {
     const size_t length = 8;
     check_caps(UCT_IFACE_FLAG_AM_BCOPY);
     mapped_buffer sendbuf(length, SEED1, *m_sender);
     mapped_buffer recvbuf(length, SEED2, *m_receiver);
     sendbuf.pattern_fill(SEED3);

     uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                              UCT_AM_CB_FLAG_ASYNC);

     /* Send until resources are exhausted */
     unsigned count = 0;
     ssize_t packed_len;
     for (;;) {
         packed_len = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                      (void*)&sendbuf);
         if (packed_len == UCS_ERR_NO_RESOURCE) {
             break;
         }

         if (packed_len >= 0) {
             ++count;
         } else {
             ASSERT_UCS_OK((ucs_status_t)packed_len);
         }
     }

     /* Queue some pending AMs */
     std::vector<test_req_t> reqs;
     reqs.resize(10);
     for (size_t i = 0; i < reqs.size(); ++i) {
         reqs[i].sendbuf    = &sendbuf;
         reqs[i].test       = this;
         reqs[i].uct.func   = am_progress;
         reqs[i].comp.count = 2;
         reqs[i].comp.func  = NULL;
         ucs_status_t status =
                         uct_ep_pending_add(m_sender->ep(0), &reqs[i].uct);
         ASSERT_UCS_OK(status);
     }

     /* Try to start a flush */
     test_req_t flush_req;
     ucs_status_t status;
     flush_req.comp.count = 2;
     flush_req.comp.func  = NULL;

     status = uct_ep_flush(m_sender->ep(0), 0, &flush_req.comp);
     if (status == UCS_OK) {
         --flush_req.comp.count;
     } else if (status == UCS_ERR_NO_RESOURCE) {
         /* If flush returned NO_RESOURCE, add to pending must succeed */
         flush_req.test      = this;
         flush_req.uct.func  = flush_progress;
         status = uct_ep_pending_add(m_sender->ep(0), &flush_req.uct);
         EXPECT_EQ(UCS_OK, status);
     } else if (status == UCS_INPROGRESS) {
     } else {
         ASSERT_UCS_OK(status);
     }

     /* coverity[loop_condition] */
     while (flush_req.comp.count != 1) {
         progress();
     }

     while (!reqs.empty()) {
         EXPECT_EQ(1, reqs.back().comp.count);
         reqs.pop_back();
     }

     m_sender->destroy_ep(0);

     short_progress_loop();

     uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

     recvbuf.pattern_check(SEED3);
}

UCT_INSTANTIATE_TEST_CASE(uct_flush_test)
<commit_msg>TEST/FLUSH: disable flush test on self transport<commit_after>/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2014.  ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/

#include "uct_p2p_test.h"

class uct_flush_test : public uct_test {
public:
    static const uint64_t SEED1 = 0x1111111111111111lu;
    static const uint64_t SEED2 = 0x2222222222222222lu;
    static const uint64_t SEED3 = 0x3333333333333333lu;
    static const int      AM_ID = 1;

    typedef void (uct_flush_test::* flush_func_t)();

    struct test_req_t {
        uct_pending_req_t  uct;
        uct_completion_t   comp;
        mapped_buffer      *sendbuf;
        uct_flush_test     *test;
    };

    void init() {
        m_sender = uct_test::create_entity(0);
        m_entities.push_back(m_sender);

        m_receiver = uct_test::create_entity(0);
        m_entities.push_back(m_receiver);

        m_sender->connect(0, *m_receiver, 0);
    }

    static size_t pack_cb(void *dest, void *arg)
    {
        const mapped_buffer *sendbuf = (const mapped_buffer *)arg;
        memcpy(dest, sendbuf->ptr(), sendbuf->length());
        return sendbuf->length();
    }

    void blocking_put_bcopy(const mapped_buffer &sendbuf,
                            const mapped_buffer &recvbuf)
    {
        ssize_t status;
         for (;;) {
             status = uct_ep_put_bcopy(m_sender->ep(0), pack_cb, (void*)&sendbuf,
                                       recvbuf.addr(), recvbuf.rkey());
             if (status >= 0) {
                 return;
             } else if (status == UCS_ERR_NO_RESOURCE) {
                 progress();
                 continue;
             } else {
                 ASSERT_UCS_OK((ucs_status_t)status);
             }
         }
    }

    void blocking_am_bcopy(const mapped_buffer &sendbuf)
    {
         ssize_t status;
         for (;;) {
             status = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                      (void*)&sendbuf);
             if (status >= 0) {
                 return;
             } else if (status == UCS_ERR_NO_RESOURCE) {
                 progress();
                 continue;
             } else {
                 ASSERT_UCS_OK((ucs_status_t)status);
             }
         }
    }

    static ucs_status_t am_handler(void *arg, void *data, size_t length,
                                   void *desc)
    {
        const mapped_buffer *recvbuf = (const mapped_buffer *)arg;
        memcpy(recvbuf->ptr(), data, ucs_min(length, recvbuf->length()));
        return UCS_OK;
    }

    ucs_status_t am_send_pending(test_req_t *am_req)
    {
        ssize_t status;

        status = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                 (void*)am_req->sendbuf);
        if (status >= 0) {
            --am_req->comp.count;
            return UCS_OK;
        } else {
            return (ucs_status_t)status;
        }
    }

    static ucs_status_t am_progress(uct_pending_req_t *req)
    {
        test_req_t *am_req = ucs_container_of(req, test_req_t, uct);
        return am_req->test->am_send_pending(am_req);
    }

    static ucs_status_t flush_progress(uct_pending_req_t *req)
    {
        test_req_t *flush_req = ucs_container_of(req, test_req_t, uct);
        ucs_status_t status;

        status = uct_ep_flush(flush_req->test->m_sender->ep(0), 0,
                              &flush_req->comp);
        if (status == UCS_OK) {
            --flush_req->comp.count;
            return UCS_OK;
        } else if (status == UCS_INPROGRESS) {
            return UCS_OK;
        } else if (status == UCS_ERR_NO_RESOURCE) {
            return UCS_ERR_NO_RESOURCE;
        } else {
            UCS_TEST_ABORT("Error: " << ucs_status_string(status));
        }
    }

    virtual void test_flush_put_bcopy(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_PUT_SHORT);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);
        blocking_put_bcopy(sendbuf, recvbuf);
        (this->*flush)();
        recvbuf.pattern_check(SEED3);
    }

    virtual void test_flush_am_zcopy(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_AM_ZCOPY);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                                 UCT_AM_CB_FLAG_ASYNC);

        uct_completion_t zcomp;
        zcomp.count = 2;
        zcomp.func  = NULL;

        ucs_status_t status;
        do {
            status = uct_ep_am_zcopy(m_sender->ep(0), AM_ID, NULL, 0, sendbuf.ptr(),
                                     sendbuf.length(), sendbuf.memh(), &zcomp);
        } while (status == UCS_ERR_NO_RESOURCE);
        ASSERT_UCS_OK_OR_INPROGRESS(status);
        if (status == UCS_OK) {
            --zcomp.count;
        }

        (this->*flush)();

        EXPECT_EQ(1, zcomp.count); /* Zero copy op should be already completed
                                      since flush returned */

        m_sender->destroy_ep(0);

        short_progress_loop();

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

        recvbuf.pattern_check(SEED3);
    }

    virtual void test_flush_am_disconnect(flush_func_t flush) {
        const size_t length = 8;
        check_caps(UCT_IFACE_FLAG_AM_BCOPY);
        mapped_buffer sendbuf(length, SEED1, *m_sender);
        mapped_buffer recvbuf(length, SEED2, *m_receiver);
        sendbuf.pattern_fill(SEED3);

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                                 UCT_AM_CB_FLAG_ASYNC);
        blocking_am_bcopy(sendbuf);
        (this->*flush)();
        m_sender->destroy_ep(0);

        short_progress_loop();

        uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

        recvbuf.pattern_check(SEED3);
    }

    void flush_ep_no_comp() {
        ucs_status_t status;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, NULL);
        } while ((status == UCS_ERR_NO_RESOURCE) || (status == UCS_INPROGRESS));
        ASSERT_UCS_OK(status);
    }

    void flush_iface_no_comp() {
        ucs_status_t status;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, NULL);
        } while ((status == UCS_ERR_NO_RESOURCE) || (status == UCS_INPROGRESS));
        ASSERT_UCS_OK(status);
    }

    void flush_ep_nb() {
        uct_completion_t comp;
        ucs_status_t status;
        comp.count = 2;
        comp.func  = NULL;
        do {
            progress();
            status = uct_ep_flush(m_sender->ep(0), 0, &comp);
        } while (status == UCS_ERR_NO_RESOURCE);
        ASSERT_UCS_OK_OR_INPROGRESS(status);
        if (status == UCS_OK) {
            return;
        }
        /* coverity[loop_condition] */
        while (comp.count != 1) {
            progress();
        }
    }

protected:
    entity *m_sender;
    entity *m_receiver;
};

UCS_TEST_P(uct_flush_test, put_bcopy_flush_ep_no_comp) {
    test_flush_put_bcopy(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, put_bcopy_flush_iface_no_comp) {
    test_flush_put_bcopy(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, put_bcopy_flush_ep_nb) {
    test_flush_put_bcopy(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_ep_no_comp) {
    test_flush_am_zcopy(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_iface_no_comp) {
    test_flush_am_zcopy(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, am_zcopy_flush_ep_nb) {
    test_flush_am_zcopy(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_flush_ep_no_comp) {
    test_flush_am_disconnect(&uct_flush_test::flush_ep_no_comp);
}

UCS_TEST_P(uct_flush_test, am_flush_iface_no_comp) {
    test_flush_am_disconnect(&uct_flush_test::flush_iface_no_comp);
}

UCS_TEST_P(uct_flush_test, am_flush_ep_nb) {
    test_flush_am_disconnect(&uct_flush_test::flush_ep_nb);
}

UCS_TEST_P(uct_flush_test, am_pending_flush_nb) {
     const size_t length = 8;
     check_caps(UCT_IFACE_FLAG_AM_BCOPY);
     mapped_buffer sendbuf(length, SEED1, *m_sender);
     mapped_buffer recvbuf(length, SEED2, *m_receiver);
     sendbuf.pattern_fill(SEED3);

     uct_iface_set_am_handler(m_receiver->iface(), AM_ID, am_handler, &recvbuf,
                              UCT_AM_CB_FLAG_ASYNC);

     /* Send until resources are exhausted */
     unsigned count = 0;
     ssize_t packed_len;
     for (;;) {
         packed_len = uct_ep_am_bcopy(m_sender->ep(0), AM_ID, pack_cb,
                                      (void*)&sendbuf);
         if (packed_len == UCS_ERR_NO_RESOURCE) {
             break;
         }

         if (packed_len >= 0) {
             ++count;
         } else {
             ASSERT_UCS_OK((ucs_status_t)packed_len);
         }
     }

     /* Queue some pending AMs */
     std::vector<test_req_t> reqs;
     reqs.resize(10);
     for (size_t i = 0; i < reqs.size(); ++i) {
         reqs[i].sendbuf    = &sendbuf;
         reqs[i].test       = this;
         reqs[i].uct.func   = am_progress;
         reqs[i].comp.count = 2;
         reqs[i].comp.func  = NULL;
         ucs_status_t status =
                         uct_ep_pending_add(m_sender->ep(0), &reqs[i].uct);
         ASSERT_UCS_OK(status);
     }

     /* Try to start a flush */
     test_req_t flush_req;
     ucs_status_t status;
     flush_req.comp.count = 2;
     flush_req.comp.func  = NULL;

     status = uct_ep_flush(m_sender->ep(0), 0, &flush_req.comp);
     if (status == UCS_OK) {
         --flush_req.comp.count;
     } else if (status == UCS_ERR_NO_RESOURCE) {
         /* If flush returned NO_RESOURCE, add to pending must succeed */
         flush_req.test      = this;
         flush_req.uct.func  = flush_progress;
         status = uct_ep_pending_add(m_sender->ep(0), &flush_req.uct);
         EXPECT_EQ(UCS_OK, status);
     } else if (status == UCS_INPROGRESS) {
     } else {
         ASSERT_UCS_OK(status);
     }

     /* coverity[loop_condition] */
     while (flush_req.comp.count != 1) {
         progress();
     }

     while (!reqs.empty()) {
         EXPECT_EQ(1, reqs.back().comp.count);
         reqs.pop_back();
     }

     m_sender->destroy_ep(0);

     short_progress_loop();

     uct_iface_set_am_handler(m_receiver->iface(), AM_ID, NULL, NULL, 0);

     recvbuf.pattern_check(SEED3);
}

UCT_INSTANTIATE_NO_SELF_TEST_CASE(uct_flush_test)
<|endoftext|>