<commit_before>// Copyright (c) 2006-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 "webkit/glue/multipart_response_delegate.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
#include "webkit/api/public/WebHTTPHeaderVisitor.h"
#include "webkit/api/public/WebString.h"
#include "webkit/api/public/WebURL.h"
#include "webkit/api/public/WebURLLoaderClient.h"
#include "webkit/glue/glue_util.h"

using WebKit::WebHTTPHeaderVisitor;
using WebKit::WebString;
using WebKit::WebURLLoader;
using WebKit::WebURLLoaderClient;
using WebKit::WebURLResponse;

namespace webkit_glue {

namespace {

// The list of response headers that we do not copy from the original
// response when generating a WebURLResponse for a MIME payload.
const char* kReplaceHeaders[] = {
  "content-type",
  "content-length",
  "content-disposition",
  "content-range",
  "range",
  "set-cookie"
};

class HeaderCopier : public WebHTTPHeaderVisitor {
 public:
  HeaderCopier(WebURLResponse* response)
      : response_(response) {
  }
  virtual void visitHeader(const WebString& name, const WebString& value) {
    const std::string& name_utf8 = WebStringToStdString(name);
    for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
      if (LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i]))
        return;
    }
    response_->setHTTPHeaderField(name, value);
  }
 private:
  WebURLResponse* response_;
};

}  // namespace

MultipartResponseDelegate::MultipartResponseDelegate(
    WebURLLoaderClient* client,
    WebURLLoader* loader,
    const WebURLResponse& response,
    const std::string& boundary)
    : client_(client),
      loader_(loader),
      original_response_(response),
      boundary_("--"),
      first_received_data_(true),
      processing_headers_(false),
      stop_sending_(false) {
  // Some servers report a boundary prefixed with "--".  See bug 5786.
  if (StartsWithASCII(boundary, "--", true)) {
    boundary_.assign(boundary);
  } else {
    boundary_.append(boundary);
  }
}

void MultipartResponseDelegate::OnReceivedData(const char* data,
                                               int data_len) {
  // stop_sending_ means that we've already received the final boundary token.
  // The server should stop sending us data at this point, but if it does, we
  // just throw it away.
  if (stop_sending_)
    return;

  // TODO(tc): Figure out what to use for length_received.  Maybe we can just
  // pass the value on from our caller.
  int length_received = -1;

  data_.append(data, data_len);
  if (first_received_data_) {
    // Some servers don't send a boundary token before the first chunk of
    // data.  We handle this case anyway (Gecko does too).
    first_received_data_ = false;

    // Eat leading \r\n
    int pos = PushOverLine(data_, 0);
    if (pos)
      data_ = data_.substr(pos);

    if (data_.length() < boundary_.length() + 2) {
      // We don't have enough data yet to make a boundary token.  Just wait
      // until the next chunk of data arrives.
      first_received_data_ = true;
      return;
    }

    if (data_.substr(0, boundary_.length()) != boundary_) {
      data_ = boundary_ + "\n" + data_;
    }
  }
  DCHECK(!first_received_data_);

  // Headers
  if (processing_headers_) {
    // Eat leading \r\n
    int pos = PushOverLine(data_, 0);
    if (pos)
      data_ = data_.substr(pos);

    if (ParseHeaders()) {
      // Successfully parsed headers.
      processing_headers_ = false;
    } else {
      // Get more data before trying again.
      return;
    }
  }
  DCHECK(!processing_headers_);

  size_t boundary_pos;
  while ((boundary_pos = FindBoundary()) != std::string::npos) {
    if (boundary_pos > 0) {
      // Send the last data chunk.
      client_->didReceiveData(loader_,
                              data_.substr(0, boundary_pos).data(),
                              static_cast<int>(boundary_pos),
                              length_received);
    }
    size_t boundary_end_pos = boundary_pos + boundary_.length();
    if (boundary_end_pos < data_.length() && '-' == data_[boundary_end_pos]) {
      // This was the last boundary so we can stop processing.
      stop_sending_ = true;
      data_.clear();
      return;
    }

    // We can now throw out data up through the boundary
    int offset = PushOverLine(data_, boundary_end_pos);
    data_ = data_.substr(boundary_end_pos + offset);

    // Ok, back to parsing headers
    if (!ParseHeaders()) {
      processing_headers_ = true;
      break;
    }
  }
}

void MultipartResponseDelegate::OnCompletedRequest() {
  // If we have any pending data and we're not in a header, go ahead and send
  // it to WebCore.
  if (!processing_headers_ && !data_.empty()) {
    // TODO(tc): Figure out what to use for length_received.  Maybe we can just
    // pass the value on from our caller.
    int length_received = -1;
    client_->didReceiveData(loader_,
                            data_.data(),
                            static_cast<int>(data_.length()),
                            length_received);
  }
}

int MultipartResponseDelegate::PushOverLine(const std::string& data,
                                            size_t pos) {
  int offset = 0;
  if (pos < data.length() && (data[pos] == '\r' || data[pos] == '\n')) {
    ++offset;
    if (pos + 1 < data.length() && data[pos + 1] == '\n')
      ++offset;
  }
  return offset;
}

bool MultipartResponseDelegate::ParseHeaders() {
  int line_feed_increment = 1;

  // Grab the headers being liberal about line endings.
  size_t line_start_pos = 0;
  size_t line_end_pos = data_.find('\n');
  while (line_end_pos != std::string::npos) {
    // Handle CRLF
    if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') {
      line_feed_increment = 2;
      --line_end_pos;
    } else {
      line_feed_increment = 1;
    }
    if (line_start_pos == line_end_pos) {
      // A blank line, end of headers
      line_end_pos += line_feed_increment;
      break;
    }
    // Find the next header line.
    line_start_pos = line_end_pos + line_feed_increment;
    line_end_pos = data_.find('\n', line_start_pos);
  }
  // Truncated in the middle of a header, stop parsing.
  if (line_end_pos == std::string::npos)
    return false;

  // Eat headers
  std::string headers("\n");
  headers.append(data_.substr(0, line_end_pos));
  data_ = data_.substr(line_end_pos);

  // Create a WebURLResponse based on the original set of headers + the
  // replacement headers.  We only replace the same few headers that gecko
  // does.  See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
  std::string mime_type = net::GetSpecificHeader(headers, "content-type");
  std::string charset = net::GetHeaderParamValue(mime_type, "charset");
  WebURLResponse response(original_response_.url());
  response.setMIMEType(StdStringToWebString(mime_type));
  response.setTextEncodingName(StdStringToWebString(charset));

  HeaderCopier copier(&response);
  original_response_.visitHTTPHeaderFields(&copier);

  for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
    std::string name(kReplaceHeaders[i]);
    std::string value = net::GetSpecificHeader(headers, name);
    if (!value.empty()) {
      response.setHTTPHeaderField(StdStringToWebString(name),
                                  StdStringToWebString(value));
    }
  }
  // Send the response!
  client_->didReceiveResponse(loader_, response);

  return true;
}

// Boundaries are supposed to be preceeded with --, but it looks like gecko
// doesn't require the dashes to exist.  See nsMultiMixedConv::FindToken.
size_t MultipartResponseDelegate::FindBoundary() {
  size_t boundary_pos = data_.find(boundary_);
  if (boundary_pos != std::string::npos) {
    // Back up over -- for backwards compat
    // TODO(tc): Don't we only want to do this once?  Gecko code doesn't seem
    // to care.
    if (boundary_pos >= 2) {
      if ('-' == data_[boundary_pos - 1] && '-' == data_[boundary_pos - 2]) {
        boundary_pos -= 2;
        boundary_ = "--" + boundary_;
      }
    }
  }
  return boundary_pos;
}

bool MultipartResponseDelegate::ReadMultipartBoundary(
    const WebURLResponse& response,
    std::string* multipart_boundary) {
  std::string content_type = WebStringToStdString(
      response.httpHeaderField(WebString::fromUTF8("Content-Type")));

  size_t boundary_start_offset = content_type.find("boundary=");
  if (boundary_start_offset == std::wstring::npos) {
    return false;
  }

  boundary_start_offset += strlen("boundary=");

  size_t boundary_end_offset = content_type.find(';', boundary_start_offset);

  if (boundary_end_offset == std::string::npos)
    boundary_end_offset = content_type.length();

  size_t boundary_length = boundary_end_offset - boundary_start_offset;

  *multipart_boundary =
      content_type.substr(boundary_start_offset, boundary_length);
  // The byte range response can have quoted boundary strings. This is legal
  // as per MIME specifications. Individual data fragements however don't
  // contain quoted boundary strings.
  TrimString(*multipart_boundary, "\"", multipart_boundary);
  return true;
}

bool MultipartResponseDelegate::ReadContentRanges(
    const WebURLResponse& response,
    int* content_range_lower_bound,
    int* content_range_upper_bound) {

  std::string content_range = WebStringToStdString(
      response.httpHeaderField(WebString::fromUTF8("Content-Range")));

  size_t byte_range_lower_bound_start_offset = content_range.find(" ");
  if (byte_range_lower_bound_start_offset == std::string::npos) {
    return false;
  }

  // Skip over the initial space.
  byte_range_lower_bound_start_offset++;

  size_t byte_range_lower_bound_end_offset =
      content_range.find("-", byte_range_lower_bound_start_offset);
  if (byte_range_lower_bound_end_offset == std::string::npos) {
    return false;
  }

  size_t byte_range_lower_bound_characters =
      byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset;
  std::string byte_range_lower_bound =
      content_range.substr(byte_range_lower_bound_start_offset,
                           byte_range_lower_bound_characters);

  size_t byte_range_upper_bound_start_offset =
      byte_range_lower_bound_end_offset + 1;

  size_t byte_range_upper_bound_end_offset =
      content_range.find("/", byte_range_upper_bound_start_offset);
  if (byte_range_upper_bound_end_offset == std::string::npos) {
    return false;
  }

  size_t byte_range_upper_bound_characters =
      byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset;

  std::string byte_range_upper_bound =
      content_range.substr(byte_range_upper_bound_start_offset,
                           byte_range_upper_bound_characters);

  if (!StringToInt(byte_range_lower_bound, content_range_lower_bound))
    return false;
  if (!StringToInt(byte_range_upper_bound, content_range_upper_bound))
    return false;
  return true;
}

}  // namespace webkit_glue
<commit_msg>Optimize memory usage in MultipartResponseDelegate by not using std::string::substr so much.<commit_after>// Copyright (c) 2006-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 "webkit/glue/multipart_response_delegate.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
#include "webkit/api/public/WebHTTPHeaderVisitor.h"
#include "webkit/api/public/WebString.h"
#include "webkit/api/public/WebURL.h"
#include "webkit/api/public/WebURLLoaderClient.h"
#include "webkit/glue/glue_util.h"

using WebKit::WebHTTPHeaderVisitor;
using WebKit::WebString;
using WebKit::WebURLLoader;
using WebKit::WebURLLoaderClient;
using WebKit::WebURLResponse;

namespace webkit_glue {

namespace {

// The list of response headers that we do not copy from the original
// response when generating a WebURLResponse for a MIME payload.
const char* kReplaceHeaders[] = {
  "content-type",
  "content-length",
  "content-disposition",
  "content-range",
  "range",
  "set-cookie"
};

class HeaderCopier : public WebHTTPHeaderVisitor {
 public:
  HeaderCopier(WebURLResponse* response)
      : response_(response) {
  }
  virtual void visitHeader(const WebString& name, const WebString& value) {
    const std::string& name_utf8 = WebStringToStdString(name);
    for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
      if (LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i]))
        return;
    }
    response_->setHTTPHeaderField(name, value);
  }
 private:
  WebURLResponse* response_;
};

}  // namespace

MultipartResponseDelegate::MultipartResponseDelegate(
    WebURLLoaderClient* client,
    WebURLLoader* loader,
    const WebURLResponse& response,
    const std::string& boundary)
    : client_(client),
      loader_(loader),
      original_response_(response),
      boundary_("--"),
      first_received_data_(true),
      processing_headers_(false),
      stop_sending_(false) {
  // Some servers report a boundary prefixed with "--".  See bug 5786.
  if (StartsWithASCII(boundary, "--", true)) {
    boundary_.assign(boundary);
  } else {
    boundary_.append(boundary);
  }
}

void MultipartResponseDelegate::OnReceivedData(const char* data,
                                               int data_len) {
  // stop_sending_ means that we've already received the final boundary token.
  // The server should stop sending us data at this point, but if it does, we
  // just throw it away.
  if (stop_sending_)
    return;

  // TODO(tc): Figure out what to use for length_received.  Maybe we can just
  // pass the value on from our caller.
  int length_received = -1;

  data_.append(data, data_len);
  if (first_received_data_) {
    // Some servers don't send a boundary token before the first chunk of
    // data.  We handle this case anyway (Gecko does too).
    first_received_data_ = false;

    // Eat leading \r\n
    int pos = PushOverLine(data_, 0);
    if (pos)
      data_ = data_.substr(pos);

    if (data_.length() < boundary_.length() + 2) {
      // We don't have enough data yet to make a boundary token.  Just wait
      // until the next chunk of data arrives.
      first_received_data_ = true;
      return;
    }

    if (0 != data_.compare(0, boundary_.length(), boundary_)) {
      data_ = boundary_ + "\n" + data_;
    }
  }
  DCHECK(!first_received_data_);

  // Headers
  if (processing_headers_) {
    // Eat leading \r\n
    int pos = PushOverLine(data_, 0);
    if (pos)
      data_ = data_.substr(pos);

    if (ParseHeaders()) {
      // Successfully parsed headers.
      processing_headers_ = false;
    } else {
      // Get more data before trying again.
      return;
    }
  }
  DCHECK(!processing_headers_);

  size_t boundary_pos;
  while ((boundary_pos = FindBoundary()) != std::string::npos) {
    if (boundary_pos > 0) {
      // Send the last data chunk.
      client_->didReceiveData(loader_,
                              data_.data(),
                              static_cast<int>(boundary_pos),
                              length_received);
    }
    size_t boundary_end_pos = boundary_pos + boundary_.length();
    if (boundary_end_pos < data_.length() && '-' == data_[boundary_end_pos]) {
      // This was the last boundary so we can stop processing.
      stop_sending_ = true;
      data_.clear();
      return;
    }

    // We can now throw out data up through the boundary
    int offset = PushOverLine(data_, boundary_end_pos);
    data_ = data_.substr(boundary_end_pos + offset);

    // Ok, back to parsing headers
    if (!ParseHeaders()) {
      processing_headers_ = true;
      break;
    }
  }
}

void MultipartResponseDelegate::OnCompletedRequest() {
  // If we have any pending data and we're not in a header, go ahead and send
  // it to WebCore.
  if (!processing_headers_ && !data_.empty()) {
    // TODO(tc): Figure out what to use for length_received.  Maybe we can just
    // pass the value on from our caller.
    int length_received = -1;
    client_->didReceiveData(loader_,
                            data_.data(),
                            static_cast<int>(data_.length()),
                            length_received);
  }
}

int MultipartResponseDelegate::PushOverLine(const std::string& data,
                                            size_t pos) {
  int offset = 0;
  if (pos < data.length() && (data[pos] == '\r' || data[pos] == '\n')) {
    ++offset;
    if (pos + 1 < data.length() && data[pos + 1] == '\n')
      ++offset;
  }
  return offset;
}

bool MultipartResponseDelegate::ParseHeaders() {
  int line_feed_increment = 1;

  // Grab the headers being liberal about line endings.
  size_t line_start_pos = 0;
  size_t line_end_pos = data_.find('\n');
  while (line_end_pos != std::string::npos) {
    // Handle CRLF
    if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') {
      line_feed_increment = 2;
      --line_end_pos;
    } else {
      line_feed_increment = 1;
    }
    if (line_start_pos == line_end_pos) {
      // A blank line, end of headers
      line_end_pos += line_feed_increment;
      break;
    }
    // Find the next header line.
    line_start_pos = line_end_pos + line_feed_increment;
    line_end_pos = data_.find('\n', line_start_pos);
  }
  // Truncated in the middle of a header, stop parsing.
  if (line_end_pos == std::string::npos)
    return false;

  // Eat headers
  std::string headers("\n");
  headers.append(data_, 0, line_end_pos);
  data_ = data_.substr(line_end_pos);

  // Create a WebURLResponse based on the original set of headers + the
  // replacement headers.  We only replace the same few headers that gecko
  // does.  See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
  std::string mime_type = net::GetSpecificHeader(headers, "content-type");
  std::string charset = net::GetHeaderParamValue(mime_type, "charset");
  WebURLResponse response(original_response_.url());
  response.setMIMEType(StdStringToWebString(mime_type));
  response.setTextEncodingName(StdStringToWebString(charset));

  HeaderCopier copier(&response);
  original_response_.visitHTTPHeaderFields(&copier);

  for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
    std::string name(kReplaceHeaders[i]);
    std::string value = net::GetSpecificHeader(headers, name);
    if (!value.empty()) {
      response.setHTTPHeaderField(StdStringToWebString(name),
                                  StdStringToWebString(value));
    }
  }
  // Send the response!
  client_->didReceiveResponse(loader_, response);

  return true;
}

// Boundaries are supposed to be preceeded with --, but it looks like gecko
// doesn't require the dashes to exist.  See nsMultiMixedConv::FindToken.
size_t MultipartResponseDelegate::FindBoundary() {
  size_t boundary_pos = data_.find(boundary_);
  if (boundary_pos != std::string::npos) {
    // Back up over -- for backwards compat
    // TODO(tc): Don't we only want to do this once?  Gecko code doesn't seem
    // to care.
    if (boundary_pos >= 2) {
      if ('-' == data_[boundary_pos - 1] && '-' == data_[boundary_pos - 2]) {
        boundary_pos -= 2;
        boundary_ = "--" + boundary_;
      }
    }
  }
  return boundary_pos;
}

bool MultipartResponseDelegate::ReadMultipartBoundary(
    const WebURLResponse& response,
    std::string* multipart_boundary) {
  std::string content_type = WebStringToStdString(
      response.httpHeaderField(WebString::fromUTF8("Content-Type")));

  size_t boundary_start_offset = content_type.find("boundary=");
  if (boundary_start_offset == std::wstring::npos) {
    return false;
  }

  boundary_start_offset += strlen("boundary=");

  size_t boundary_end_offset = content_type.find(';', boundary_start_offset);

  if (boundary_end_offset == std::string::npos)
    boundary_end_offset = content_type.length();

  size_t boundary_length = boundary_end_offset - boundary_start_offset;

  *multipart_boundary =
      content_type.substr(boundary_start_offset, boundary_length);
  // The byte range response can have quoted boundary strings. This is legal
  // as per MIME specifications. Individual data fragements however don't
  // contain quoted boundary strings.
  TrimString(*multipart_boundary, "\"", multipart_boundary);
  return true;
}

bool MultipartResponseDelegate::ReadContentRanges(
    const WebURLResponse& response,
    int* content_range_lower_bound,
    int* content_range_upper_bound) {

  std::string content_range = WebStringToStdString(
      response.httpHeaderField(WebString::fromUTF8("Content-Range")));

  size_t byte_range_lower_bound_start_offset = content_range.find(" ");
  if (byte_range_lower_bound_start_offset == std::string::npos) {
    return false;
  }

  // Skip over the initial space.
  byte_range_lower_bound_start_offset++;

  size_t byte_range_lower_bound_end_offset =
      content_range.find("-", byte_range_lower_bound_start_offset);
  if (byte_range_lower_bound_end_offset == std::string::npos) {
    return false;
  }

  size_t byte_range_lower_bound_characters =
      byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset;
  std::string byte_range_lower_bound =
      content_range.substr(byte_range_lower_bound_start_offset,
                           byte_range_lower_bound_characters);

  size_t byte_range_upper_bound_start_offset =
      byte_range_lower_bound_end_offset + 1;

  size_t byte_range_upper_bound_end_offset =
      content_range.find("/", byte_range_upper_bound_start_offset);
  if (byte_range_upper_bound_end_offset == std::string::npos) {
    return false;
  }

  size_t byte_range_upper_bound_characters =
      byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset;

  std::string byte_range_upper_bound =
      content_range.substr(byte_range_upper_bound_start_offset,
                           byte_range_upper_bound_characters);

  if (!StringToInt(byte_range_lower_bound, content_range_lower_bound))
    return false;
  if (!StringToInt(byte_range_upper_bound, content_range_upper_bound))
    return false;
  return true;
}

}  // namespace webkit_glue
<|endoftext|>


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

#include "webkit/support/platform_support.h"

#include "base/android/jni_android.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/string_piece.h"
#include "base/test/test_support_android.h"
#include "googleurl/src/gurl.h"
#include "grit/webkit_resources.h"
#include "net/android/network_library.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/support/test_webkit_platform_support.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"

namespace {

// The place where the Android layout test script will put the required tools
// and resources. Must keep consistent with DEVICE_DRT_DIR in
// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py.
// TODO(wangxianzhu): Allow running DRT on non-rooted device by putting
// the tools and resources into the apk or under /data/local/tmp.
const char kDumpRenderTreeDir[] = "/data/drt";

}

namespace webkit_support {

void BeforeInitialize(bool unit_test_mode) {
  base::InitAndroidTestPaths();

  // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from
  // loading and complaining the non-exsistent /etc/xml/catalog file.
  setenv("XML_CATALOG_FILES", "", 0);

  // For now TestWebKitAPI and webkit_unit_tests are standalone executables
  // which don't have Java capabilities. Init Java for only DumpRenderTree.
  if (!unit_test_mode) {
    JNIEnv* env = base::android::AttachCurrentThread();
    net::android::RegisterNetworkLibrary(env);
  }
}

void AfterInitialize(bool unit_test_mode) {
  if (unit_test_mode)
    return;  // We don't have a resource pack when running the unit-tests.

  FilePath data_path(kDumpRenderTreeDir);
  data_path = data_path.Append("DumpRenderTree.pak");
  ResourceBundle::InitSharedInstanceWithPakPath(data_path);

  // We enable file-over-http to bridge the file protocol to http protocol
  // in here, which can
  // (1) run the layout tests on android target device, but never need to
  // push the test files and corresponding resources to device, which saves
  // huge running time.
  // (2) still run non-http layout (tests not under LayoutTests/http) tests
  // via file protocol without breaking test environment / convention of webkit
  // layout tests, which are followed by current all webkit ports.
  SimpleResourceLoaderBridge::AllowFileOverHTTP(
      "third_party/WebKit/LayoutTests/",
      GURL("http://127.0.0.1:8000/all-tests/"));
}

void BeforeShutdown() {
  ResourceBundle::CleanupSharedInstance();
}

void AfterShutdown() {
}

}  // namespace webkit_support

string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) {
  return ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
}

base::StringPiece TestWebKitPlatformSupport::GetDataResource(
    int resource_id,
    ui::ScaleFactor scale_factor) {
  FilePath resources_path(kDumpRenderTreeDir);
  resources_path = resources_path.Append("DumpRenderTree_resources");
  switch (resource_id) {
    case IDR_BROKENIMAGE: {
      CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ());
      if (broken_image_data.empty()) {
        FilePath path = resources_path.Append("missingImage.gif");
        bool success = file_util::ReadFileToString(path, &broken_image_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return broken_image_data;
    }
    case IDR_TEXTAREA_RESIZER: {
      CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ());
      if (resize_corner_data.empty()) {
        FilePath path = resources_path.Append("textAreaResizeCorner.png");
        bool success = file_util::ReadFileToString(path, &resize_corner_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return resize_corner_data;
    }
  }

  return ResourceBundle::GetSharedInstance().GetRawDataResource(
      resource_id, scale_factor);
}
<commit_msg>Change of DumpRenderTree directory on Android.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/support/platform_support.h"

#include "base/android/jni_android.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/string_piece.h"
#include "base/test/test_support_android.h"
#include "googleurl/src/gurl.h"
#include "grit/webkit_resources.h"
#include "net/android/network_library.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/support/test_webkit_platform_support.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"

namespace {

// The place where the Android layout test script will put the required tools
// and resources. Must keep consistent with DEVICE_DRT_DIR in
// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py.
const char kDumpRenderTreeDir[] = "/data/local/tmp/drt";

}

namespace webkit_support {

void BeforeInitialize(bool unit_test_mode) {
  base::InitAndroidTestPaths();

  // Place cache under kDumpRenderTreeDir to allow the NRWT script to clear it.
  FilePath path(kDumpRenderTreeDir);
  path = path.Append("cache");
  PathService::Override(base::DIR_CACHE, path);

  // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from
  // loading and complaining the non-exsistent /etc/xml/catalog file.
  setenv("XML_CATALOG_FILES", "", 0);

  // For now TestWebKitAPI and webkit_unit_tests are standalone executables
  // which don't have Java capabilities. Init Java for only DumpRenderTree.
  if (!unit_test_mode) {
    JNIEnv* env = base::android::AttachCurrentThread();
    net::android::RegisterNetworkLibrary(env);
  }
}

void AfterInitialize(bool unit_test_mode) {
  if (unit_test_mode)
    return;  // We don't have a resource pack when running the unit-tests.

  FilePath data_path(kDumpRenderTreeDir);
  data_path = data_path.Append("DumpRenderTree.pak");
  ResourceBundle::InitSharedInstanceWithPakPath(data_path);

  // We enable file-over-http to bridge the file protocol to http protocol
  // in here, which can
  // (1) run the layout tests on android target device, but never need to
  // push the test files and corresponding resources to device, which saves
  // huge running time.
  // (2) still run non-http layout (tests not under LayoutTests/http) tests
  // via file protocol without breaking test environment / convention of webkit
  // layout tests, which are followed by current all webkit ports.
  SimpleResourceLoaderBridge::AllowFileOverHTTP(
      "third_party/WebKit/LayoutTests/",
      GURL("http://127.0.0.1:8000/all-tests/"));
}

void BeforeShutdown() {
  ResourceBundle::CleanupSharedInstance();
}

void AfterShutdown() {
}

}  // namespace webkit_support

string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) {
  return ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
}

base::StringPiece TestWebKitPlatformSupport::GetDataResource(
    int resource_id,
    ui::ScaleFactor scale_factor) {
  FilePath resources_path(kDumpRenderTreeDir);
  resources_path = resources_path.Append("DumpRenderTree_resources");
  switch (resource_id) {
    case IDR_BROKENIMAGE: {
      CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ());
      if (broken_image_data.empty()) {
        FilePath path = resources_path.Append("missingImage.gif");
        bool success = file_util::ReadFileToString(path, &broken_image_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return broken_image_data;
    }
    case IDR_TEXTAREA_RESIZER: {
      CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ());
      if (resize_corner_data.empty()) {
        FilePath path = resources_path.Append("textAreaResizeCorner.png");
        bool success = file_util::ReadFileToString(path, &resize_corner_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return resize_corner_data;
    }
  }

  return ResourceBundle::GetSharedInstance().GetRawDataResource(
      resource_id, scale_factor);
}
<|endoftext|>


<commit_before>/**
 * OpenBoardView
 *
 * Copyright inflex 2016 (Paul Daniels)
 * Copyright chloridite 2016
 *
 * https://github.com/OpenBoardView/OpenBoardView
 *
 */

#include "platform.h" // Should be kept first
#include "utils.h"
#include "version.h"

#include "BoardView.h"
#include "history.h"

#include "FileFormats/FZFile.h"
#include "confparse.h"
#include "resource.h"
#ifdef _MSC_VER
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include <deque>
#include <memory>
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif

// Rendering stuff
#include "Renderers/Renderers.h"

struct globals {
	char *input_file;
	char *config_file;
	bool slowCPU;
	int width;
	int height;
	int dpi;
	double font_size;
	bool debug;
	Renderers::Renderer renderer;

	globals() {
		this->input_file  = NULL;
		this->config_file = NULL;
		this->slowCPU     = false;
		this->width       = 0;
		this->height      = 0;
		this->dpi         = 0;
		this->font_size   = 0.0f;
		this->debug       = false;
		this->renderer    = Renderers::Renderer::DEFAULT;
	}
};

static SDL_Window *window      = nullptr;

char help[] =
    " [-h] [-V] [-l] [-c <config file>] [-i <intput file>] [-x <width>] [-y <height>] [-z <fontsize>] [-p <dpi>] [-r <renderer>] [-d]\n\
	-h : This help\n\
	-V : Version information\n\
	-l : slow CPU mode, disables AA and other items to try provide more FPS\n\
	-c <config file> : alternative configuration file (default is ~/.config/" OBV_NAME
    "/obv.conf)\n\
	-i <input file> : board file to load\n\
	-x <width> : Set window width\n\
	-y <height> : Set window height\n\
	-z <pixels> : Set font size\n\
	-p <dpi> : Set the dpi\n\
	-r <renderer> : Set the renderer [ OPENGL1 = 1; OPENGL3 = 2; OPENGLES2 = 3 ]\n\
	-d : Debug mode\n\
";

int parse_parameters(int argc, char **argv, struct globals *g) {
	int param;

	/*
	 * When we're using file-associations, the OS usually just
	 * passes the filename to be loaded as the single initial
	 * parameter, so in this special case situation we see if the
	 * single param is a valid file, and try load it.
	 */
	if (argc == 2) {
		if (access(argv[1], F_OK) != -1) {
			g->input_file = argv[1];
			return 0;
		}
	}

	/**
	 * Decode the input parameters.
	 * Yes, I know, I should do this using gnu params etc.
	 */
	for (param = 1; param < argc; param++) {
		char *p = argv[param];

		if (strcmp(p, "-h") == 0) {
			fprintf(stdout, "%s %s", argv[0], help);
			exit(0);
		}

		if (strcmp(p, "-V") == 0) {
			fprintf(stdout, "OFBV-BUILD: %s %s\n", OBV_BUILD, __TIMESTAMP__);
			exit(0);
		}

		// Configuration file (alternative)
		if (strcmp(p, "-c") == 0) {
			param++;
			if (param < argc) {
				g->config_file = argv[param];
			} else {
				fprintf(stderr, "Not enough paramters\n");
				exit(1);
			}

		} else if (strcmp(p, "-i") == 0) {
			param++;
			if (param < argc) {
				g->input_file = argv[param];
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-x") == 0) {
			param++;
			if (param < argc) {
				g->width = strtol(argv[param], NULL, 10);
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-y") == 0) {
			param++;
			if (param < argc) {
				g->height = strtol(argv[param], NULL, 10);
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-z") == 0) {
			param++;
			if (param < argc) {
				g->font_size = strtof(argv[param], NULL);
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-p") == 0) {
			param++;
			if (param < argc) {
				g->dpi = strtof(argv[param], NULL);
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-r") == 0) {
			param++;
			if (param < argc) {
				g->renderer = Renderers::get(atoi(argv[param]));
			} else {
				fprintf(stderr, "Not enough parameters\n");
			}

		} else if (strcmp(p, "-l") == 0) {
			g->slowCPU = true;

		} else if (strcmp(p, "-d") == 0) {
			g->debug = true;

			/*
			 * for extended parameters, nothing yet required
			 *
			 *
		  } else if (strncmp(p,"--", 2) == 0) {

			 */
		}
	}

	return 0;
}

void cleanupAndExit(int c) {
	if (window) SDL_DestroyWindow(window);
	SDL_Quit();
	exit(c);
}

int main(int argc, char **argv) {
	uint8_t sleepout;
	std::string configDir;
	globals g; // because some things we have to store *before* we load the config file in BoardView app.obvconf
	BoardView app{};

	/*
	 * Parse the parameters first up, store the results in the global struct.
	 *
	 * This does mean a little more redundancy between the OS builds but not
	 * as bad as it was before.
	 *
	 */
	parse_parameters(argc, argv, &g);

	app.debug = g.debug;

	// Setup SDL
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
		printf("Error: %s\n", SDL_GetError());
		return -1;
	}
	SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);

	// Load the configuration file
	configDir = get_user_dir(UserDir::Config);
	if (!configDir.empty()) app.obvconfig.Load(configDir + "obv.conf");

	// Load file history
	std::string dataDir = get_user_dir(UserDir::Data);
	if (!dataDir.empty()) {
		app.fhistory.Set_filename(dataDir + "obv.history");
		app.fhistory.Load();
	}

	// If we've chosen to override the normally found config.
	if (g.config_file) app.obvconfig.Load(g.config_file);

	// Apply the slowCPU flag if required.
	app.slowCPU = g.slowCPU;

	if (g.width == 0) g.width   = app.obvconfig.ParseInt("windowX", 1100);
	if (g.height == 0) g.height = app.obvconfig.ParseInt("windowY", 700);

	if (g.renderer == Renderers::Renderer::DEFAULT) {
		g.renderer = Renderers::get(app.obvconfig.ParseInt("renderer", static_cast<int>(Renderers::Preferred)));
	}

	// Setup window
	SDL_DisplayMode current;
	SDL_GetCurrentDisplayMode(0, &current);
	window = SDL_CreateWindow(
	    OBV_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, g.width, g.height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (window == NULL) {
		SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create the sdlWindow: %s\n", SDL_GetError());
		cleanupAndExit(1);
	}

	// Setup renderer
	std::unique_ptr<ImGuiRendererSDL> renderer = Renderers::initBestRenderer(g.renderer, window);
	if (!renderer) {
		SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", "No renderer not available. Exiting.");
		cleanupAndExit(1);
	}

	SDL_EventState(SDL_DROPFILE, SDL_ENABLE);

	// SDL disables screen saver by default which doesn't make sense for us.
	SDL_EnableScreenSaver();

	ImGuiIO &io    = ImGui::GetIO();
	io.IniFilename = NULL;
	//	io.Fonts->AddFontDefault();

	// Main loop
	bool done             = false;
	bool preload_required = false;

	// Set the dpi, if we've not set any parameters it'll be 0 which
	// will make the ConfigParse load and set the right dpi.
	app.dpi = g.dpi;

	// Now that the configuration file is loaded in to BoardView, parse its settings.
	app.ConfigParse();

	// Preset some workable sizes
	app.m_board_surface.x = g.width;
	app.m_board_surface.y = g.height;
	if (app.showInfoPanel) app.m_board_surface.x -= app.m_info_surface.x;

	if (g.font_size == 0.0f) g.font_size = app.obvconfig.ParseDouble("fontSize", 20.0f);
	g.font_size                          = (g.font_size * app.dpi) / 100;

	{
		ImGuiStyle &style = ImGui::GetStyle();
		style.ScrollbarSize *= app.dpi / 100;
	}

	// Font selection
	std::deque<std::string> fontList(
	    {"Liberation Sans", "DejaVu Sans", "Arial", "Helvetica", ""}); // Empty string = use system default font
	std::string customFont(app.obvconfig.ParseStr("fontName", ""));

	if (!customFont.empty()) fontList.push_front(customFont);

	for (const auto &name : fontList) {
		app.obvconfig.WriteStr("fontName", name.c_str());
#ifdef _WIN32
		ImFontConfig font_cfg{};
		font_cfg.FontDataOwnedByAtlas = false;
		const std::vector<char> ttf   = load_font(name);
		if (!ttf.empty()) {
			io.Fonts->AddFontFromMemoryTTF(
			    const_cast<void *>(reinterpret_cast<const void *>(ttf.data())), ttf.size(), g.font_size, &font_cfg);
			break;
		}
#else
		const std::string fontpath = get_font_path(name);
		if (fontpath.empty()) continue;        // Font not found
		if (check_fileext(fontpath, ".ttf")) { // ImGui handles only TrueType fonts so exclude anything which has a different ext
			io.Fonts->AddFontFromFileTTF(fontpath.c_str(), g.font_size);
			break;
		}
#endif
	}

	// ImVec4 clear_color = ImColor(20, 20, 30);
	ImVec4 clear_color = ImColor(app.m_colors.backgroundColor);

	/*
	 * If we've asked to load a file from the command line
	 * then this is where we stage it to be loaded directly
	 * in to OBV
	 */
	if (g.input_file) {
		struct stat buffer;
		if ((stat(g.input_file, &buffer) == 0)) {
			preload_required = true;
		}
	}

	/*
	 * The sleepout var keeps track of how many iterations of the main loop
	 * are left, without an event having happened before OBV will start to sleep
	 * and continue without redrawing the page.
	 *
	 * The reason we don't just sleep immediately after a non-event is because
	 * sometimes there are internal things that still need to be done on the next
	 * render (such as responding to a mouse click
	 *
	 * For now we've got this set to 3 frames which seems to work okay with OBV.
	 * If you find some things aren't working properly without you having to move
	 * the mouse or 'waking up' OBV then increase to 5 or more.
	 */
	sleepout = 3;
	while (!done) {

		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			sleepout = 3;
			renderer->processEvent(event);

			if (event.type == SDL_DROPFILE) {
				// Validate the file before replacing the current one, not that we
				// should have to, but always better to be safe
				struct stat buffer;
				if (stat(event.drop.file, &buffer) == 0) {
					app.LoadFile(strdup(event.drop.file));
				}
			}

			if (event.type == SDL_QUIT) done = true;
		}

		if (app.reloadConfig) {
			app.reloadConfig = false;
			app.obvconfig.Load(configDir + "obv.conf");
			app.ConfigParse();
			clear_color = ImColor(app.m_colors.backgroundColor);
		}

		if (!(sleepout--)) {
#ifdef _WIN32
			Sleep(50);
#else
			usleep(50000);
#endif
			sleepout = 0;
			continue;
		} // puts OBV to sleep if nothing is happening.

		// Prepare frame
		renderer->initFrame();

		// If we have a board to view being passed from command line, then "inject"
		// it here.
		if (preload_required) {
			app.LoadFile(strdup(g.input_file));
			preload_required = false;
		}

		app.Update();
		if (app.m_wantsQuit) {
			SDL_Event sdlevent;
			sdlevent.type = SDL_QUIT;
			SDL_PushEvent(&sdlevent);
		}

		// Update the title of the SDL app if the board filename has changed. -
		// PLD20160618
		if (app.history_file_has_changed) {
			char scratch[1024];
			snprintf(scratch, sizeof(scratch), "%s - %s", OBV_NAME, app.fhistory.history[0]);
			SDL_SetWindowTitle(window, scratch);
			app.history_file_has_changed = 0;
		}

		// Render frame
		renderer->renderFrame(clear_color);
	}

	// Cleanup
 	renderer->shutdown();

	cleanupAndExit(0);
	return 0;
}
<commit_msg>Improve CLI parameter handling and use default failure on bad parameters<commit_after>/**
 * OpenBoardView
 *
 * Copyright inflex 2016 (Paul Daniels)
 * Copyright chloridite 2016
 *
 * https://github.com/OpenBoardView/OpenBoardView
 *
 */

#include "platform.h" // Should be kept first
#include "utils.h"
#include "version.h"

#include "BoardView.h"
#include "history.h"

#include "FileFormats/FZFile.h"
#include "confparse.h"
#include "resource.h"
#ifdef _MSC_VER
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include <deque>
#include <memory>
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif

// Rendering stuff
#include "Renderers/Renderers.h"

struct globals {
	char *input_file;
	char *config_file;
	bool slowCPU;
	int width;
	int height;
	int dpi;
	double font_size;
	bool debug;
	Renderers::Renderer renderer;

	globals() {
		this->input_file  = NULL;
		this->config_file = NULL;
		this->slowCPU     = false;
		this->width       = 0;
		this->height      = 0;
		this->dpi         = 0;
		this->font_size   = 0.0f;
		this->debug       = false;
		this->renderer    = Renderers::Renderer::DEFAULT;
	}
};

static SDL_Window *window      = nullptr;

char help[] =
    " [-h] [-V] [-l] [-c <config file>] [-i <intput file>] [-x <width>] [-y <height>] [-z <fontsize>] [-p <dpi>] [-r <renderer>] [-d]\n\
	-h : This help\n\
	-V : Version information\n\
	-l : slow CPU mode, disables AA and other items to try provide more FPS\n\
	-c <config file> : alternative configuration file (default is ~/.config/" OBV_NAME
    "/obv.conf)\n\
	-i <input file> : board file to load\n\
	-x <width> : Set window width\n\
	-y <height> : Set window height\n\
	-z <pixels> : Set font size\n\
	-p <dpi> : Set the dpi\n\
	-r <renderer> : Set the renderer [ OPENGL1 = 1; OPENGL3 = 2; OPENGLES2 = 3 ]\n\
	-d : Debug mode\n\
";

int parse_parameters(int argc, char **argv, struct globals *g) {
	int param;

	/*
	 * When we're using file-associations, the OS usually just
	 * passes the filename to be loaded as the single initial
	 * parameter, so in this special case situation we see if the
	 * single param is a valid file, and try load it.
	 */
	if (argc == 2) {
		if (access(argv[1], F_OK) != -1) {
			g->input_file = argv[1];
			return 0;
		}
	}

	/**
	 * Decode the input parameters.
	 * Yes, I know, I should do this using gnu params etc.
	 */
	for (param = 1; param < argc; param++) {
		char *p = argv[param];

		if (strcmp(p, "-h") == 0) {
			fprintf(stdout, "%s %s", argv[0], help);
			exit(0);
		}

		if (strcmp(p, "-V") == 0) {
			fprintf(stdout, "OFBV-BUILD: %s %s\n", OBV_BUILD, __TIMESTAMP__);
			exit(0);
		}

		// Configuration file (alternative)
		if (strcmp(p, "-c") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->config_file = argv[param];
			} else {
				fprintf(stderr, "Not enough paramters for -c <config>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-i") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->input_file = argv[param];
			} else {
				fprintf(stderr, "Not enough paramters for -i <input file>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-x") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->width = strtol(argv[param], NULL, 10);
			} else {
				fprintf(stderr, "Not enough paramters for -x <window width>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-y") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->height = strtol(argv[param], NULL, 10);
			} else {
				fprintf(stderr, "Not enough paramters for -y <window height>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-z") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->font_size = strtof(argv[param], NULL);
			} else {
				fprintf(stderr, "Not enough paramters for -z <font size>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-p") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->dpi = strtof(argv[param], NULL);
			} else {
				fprintf(stderr, "Not enough paramters for -p <dpi>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-r") == 0) {
			param++;
			if ((param < argc)&&(argv[param][0] != '-')) {
				g->renderer = Renderers::get(atoi(argv[param]));
			} else {
				fprintf(stderr, "Not enough paramters for -r <render engine>\n\n%s %s", argv[0], help );
				exit(1);
			}

		} else if (strcmp(p, "-l") == 0) {
			g->slowCPU = true;

		} else if (strcmp(p, "-d") == 0) {
			g->debug = true;

			/*
			 * for extended parameters, nothing yet required
			 *
			 *
		  } else if (strncmp(p,"--", 2) == 0) {

			 */
		} else {
			fprintf(stderr, "Unknown parameter '%s'\n\n%s %s", p, argv[0], help);
			exit(1);
		}
	}

	return 0;
}

void cleanupAndExit(int c) {
	if (window) SDL_DestroyWindow(window);
	SDL_Quit();
	exit(c);
}

int main(int argc, char **argv) {
	uint8_t sleepout;
	std::string configDir;
	globals g; // because some things we have to store *before* we load the config file in BoardView app.obvconf
	BoardView app{};

	/*
	 * Parse the parameters first up, store the results in the global struct.
	 *
	 * This does mean a little more redundancy between the OS builds but not
	 * as bad as it was before.
	 *
	 */
	parse_parameters(argc, argv, &g);

	app.debug = g.debug;

	// Setup SDL
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
		printf("Error: %s\n", SDL_GetError());
		return -1;
	}
	SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);

	// Load the configuration file
	configDir = get_user_dir(UserDir::Config);
	if (!configDir.empty()) app.obvconfig.Load(configDir + "obv.conf");

	// Load file history
	std::string dataDir = get_user_dir(UserDir::Data);
	if (!dataDir.empty()) {
		app.fhistory.Set_filename(dataDir + "obv.history");
		app.fhistory.Load();
	}

	// If we've chosen to override the normally found config.
	if (g.config_file) app.obvconfig.Load(g.config_file);

	// Apply the slowCPU flag if required.
	app.slowCPU = g.slowCPU;

	if (g.width == 0) g.width   = app.obvconfig.ParseInt("windowX", 1100);
	if (g.height == 0) g.height = app.obvconfig.ParseInt("windowY", 700);

	if (g.renderer == Renderers::Renderer::DEFAULT) {
		g.renderer = Renderers::get(app.obvconfig.ParseInt("renderer", static_cast<int>(Renderers::Preferred)));
	}

	// Setup window
	SDL_DisplayMode current;
	SDL_GetCurrentDisplayMode(0, &current);
	window = SDL_CreateWindow(
	    OBV_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, g.width, g.height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (window == NULL) {
		SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create the sdlWindow: %s\n", SDL_GetError());
		cleanupAndExit(1);
	}

	// Setup renderer
	std::unique_ptr<ImGuiRendererSDL> renderer = Renderers::initBestRenderer(g.renderer, window);
	if (!renderer) {
		SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", "No renderer not available. Exiting.");
		cleanupAndExit(1);
	}

	SDL_EventState(SDL_DROPFILE, SDL_ENABLE);

	// SDL disables screen saver by default which doesn't make sense for us.
	SDL_EnableScreenSaver();

	ImGuiIO &io    = ImGui::GetIO();
	io.IniFilename = NULL;
	//	io.Fonts->AddFontDefault();

	// Main loop
	bool done             = false;
	bool preload_required = false;

	// Set the dpi, if we've not set any parameters it'll be 0 which
	// will make the ConfigParse load and set the right dpi.
	app.dpi = g.dpi;

	// Now that the configuration file is loaded in to BoardView, parse its settings.
	app.ConfigParse();

	// Preset some workable sizes
	app.m_board_surface.x = g.width;
	app.m_board_surface.y = g.height;
	if (app.showInfoPanel) app.m_board_surface.x -= app.m_info_surface.x;

	if (g.font_size == 0.0f) g.font_size = app.obvconfig.ParseDouble("fontSize", 20.0f);
	g.font_size                          = (g.font_size * app.dpi) / 100;

	{
		ImGuiStyle &style = ImGui::GetStyle();
		style.ScrollbarSize *= app.dpi / 100;
	}

	// Font selection
	std::deque<std::string> fontList(
	    {"Liberation Sans", "DejaVu Sans", "Arial", "Helvetica", ""}); // Empty string = use system default font
	std::string customFont(app.obvconfig.ParseStr("fontName", ""));

	if (!customFont.empty()) fontList.push_front(customFont);

	for (const auto &name : fontList) {
		app.obvconfig.WriteStr("fontName", name.c_str());
#ifdef _WIN32
		ImFontConfig font_cfg{};
		font_cfg.FontDataOwnedByAtlas = false;
		const std::vector<char> ttf   = load_font(name);
		if (!ttf.empty()) {
			io.Fonts->AddFontFromMemoryTTF(
			    const_cast<void *>(reinterpret_cast<const void *>(ttf.data())), ttf.size(), g.font_size, &font_cfg);
			break;
		}
#else
		const std::string fontpath = get_font_path(name);
		if (fontpath.empty()) continue;        // Font not found
		if (check_fileext(fontpath, ".ttf")) { // ImGui handles only TrueType fonts so exclude anything which has a different ext
			io.Fonts->AddFontFromFileTTF(fontpath.c_str(), g.font_size);
			break;
		}
#endif
	}

	// ImVec4 clear_color = ImColor(20, 20, 30);
	ImVec4 clear_color = ImColor(app.m_colors.backgroundColor);

	/*
	 * If we've asked to load a file from the command line
	 * then this is where we stage it to be loaded directly
	 * in to OBV
	 */
	if (g.input_file) {
		struct stat buffer;
		if ((stat(g.input_file, &buffer) == 0)) {
			preload_required = true;
		}
	}

	/*
	 * The sleepout var keeps track of how many iterations of the main loop
	 * are left, without an event having happened before OBV will start to sleep
	 * and continue without redrawing the page.
	 *
	 * The reason we don't just sleep immediately after a non-event is because
	 * sometimes there are internal things that still need to be done on the next
	 * render (such as responding to a mouse click
	 *
	 * For now we've got this set to 3 frames which seems to work okay with OBV.
	 * If you find some things aren't working properly without you having to move
	 * the mouse or 'waking up' OBV then increase to 5 or more.
	 */
	sleepout = 3;
	while (!done) {

		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			sleepout = 3;
			renderer->processEvent(event);

			if (event.type == SDL_DROPFILE) {
				// Validate the file before replacing the current one, not that we
				// should have to, but always better to be safe
				struct stat buffer;
				if (stat(event.drop.file, &buffer) == 0) {
					app.LoadFile(strdup(event.drop.file));
				}
			}

			if (event.type == SDL_QUIT) done = true;
		}

		if (app.reloadConfig) {
			app.reloadConfig = false;
			app.obvconfig.Load(configDir + "obv.conf");
			app.ConfigParse();
			clear_color = ImColor(app.m_colors.backgroundColor);
		}

		if (!(sleepout--)) {
#ifdef _WIN32
			Sleep(50);
#else
			usleep(50000);
#endif
			sleepout = 0;
			continue;
		} // puts OBV to sleep if nothing is happening.

		// Prepare frame
		renderer->initFrame();

		// If we have a board to view being passed from command line, then "inject"
		// it here.
		if (preload_required) {
			app.LoadFile(strdup(g.input_file));
			preload_required = false;
		}

		app.Update();
		if (app.m_wantsQuit) {
			SDL_Event sdlevent;
			sdlevent.type = SDL_QUIT;
			SDL_PushEvent(&sdlevent);
		}

		// Update the title of the SDL app if the board filename has changed. -
		// PLD20160618
		if (app.history_file_has_changed) {
			char scratch[1024];
			snprintf(scratch, sizeof(scratch), "%s - %s", OBV_NAME, app.fhistory.history[0]);
			SDL_SetWindowTitle(window, scratch);
			app.history_file_has_changed = 0;
		}

		// Render frame
		renderer->renderFrame(clear_color);
	}

	// Cleanup
 	renderer->shutdown();

	cleanupAndExit(0);
	return 0;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qlibrary.h>
#include <qdebug.h>
#include <private/qgl_p.h>
#include <private/qt_x11_p.h>
#include <private/qpaintengine_opengl_p.h>

#include <qx11info_x11.h>
#include <GL/glx.h>
#include <qimage.h>

#include "qglpixelbuffer.h"
#include "qglpixelbuffer_p.h"

#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
#include <dlfcn.h>
#endif

QT_BEGIN_NAMESPACE

#ifndef GLX_VERSION_1_3
#define GLX_RGBA_BIT            0x00000002
#define GLX_PBUFFER_BIT         0x00000004
#define GLX_DRAWABLE_TYPE       0x8010
#define GLX_RENDER_TYPE         0x8011
#define GLX_RGBA_TYPE           0x8014
#define GLX_PBUFFER_HEIGHT      0x8040
#define GLX_PBUFFER_WIDTH       0x8041
#endif

#ifndef GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB  100000
#define GLX_SAMPLES_ARB         100001
#endif

typedef GLXFBConfig* (*_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
typedef int (*_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
typedef GLXPbuffer (*_glXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attrib_list);
typedef void (*_glXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf);
typedef GLXContext (*_glXCreateNewContext) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
typedef Bool (*_glXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);

static _glXChooseFBConfig qt_glXChooseFBConfig = 0;
static _glXCreateNewContext qt_glXCreateNewContext = 0;
static _glXCreatePbuffer qt_glXCreatePbuffer = 0;
static _glXDestroyPbuffer qt_glXDestroyPbuffer = 0;
static _glXGetFBConfigAttrib qt_glXGetFBConfigAttrib = 0;
static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;

#define glXChooseFBConfig qt_glXChooseFBConfig
#define glXCreateNewContext qt_glXCreateNewContext
#define glXCreatePbuffer qt_glXCreatePbuffer
#define glXDestroyPbuffer qt_glXDestroyPbuffer
#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
#define glXMakeContextCurrent qt_glXMakeContextCurrent

extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp

static bool qt_resolve_pbuffer_extensions()
{
    static int resolved = false;
    if (resolved && qt_glXMakeContextCurrent)
        return true;
    else if (resolved)
        return false;

    qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig");
    qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext");
    qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer");
    qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer");
    qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib");
    qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent");

    resolved = qt_glXMakeContextCurrent ? true : false;
    return resolved;
}

static void qt_format_to_attrib_list(const QGLFormat &f, int attribs[])
{
    int i = 0;
    attribs[i++] = GLX_RENDER_TYPE;
    attribs[i++] = GLX_RGBA_BIT;
    attribs[i++] = GLX_DRAWABLE_TYPE;
    attribs[i++] = GLX_PBUFFER_BIT;
    attribs[i++] = GLX_RED_SIZE;
    attribs[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
    attribs[i++] = GLX_GREEN_SIZE;
    attribs[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
    attribs[i++] = GLX_BLUE_SIZE;
    attribs[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
    if (f.doubleBuffer()) {
        attribs[i++] = GLX_DOUBLEBUFFER;
        attribs[i++] = true;
    }
    if (f.depth()) {
        attribs[i++] = GLX_DEPTH_SIZE;
        attribs[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
    }
    if (f.stereo()) {
        attribs[i++] = GLX_STEREO;
        attribs[i++] = true;
    }
    if (f.stencil()) {
        attribs[i++] = GLX_STENCIL_SIZE;
        attribs[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
    }
    if (f.alpha()) {
        attribs[i++] = GLX_ALPHA_SIZE;
        attribs[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
    }
    if (f.accum()) {
        attribs[i++] = GLX_ACCUM_RED_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        attribs[i++] = GLX_ACCUM_GREEN_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        attribs[i++] = GLX_ACCUM_BLUE_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        if (f.alpha()) {
            attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
            attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        }
    }
    if (f.sampleBuffers()) {
        attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
        attribs[i++] = 1;
        attribs[i++] = GLX_SAMPLES_ARB;
        attribs[i++] = f.samples() == -1 ? 4 : f.samples();
    }

    attribs[i] = XNone;
}

bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget)
{
    if (!qt_resolve_pbuffer_extensions()) {
        qWarning("QGLPixelBuffer: pbuffers are not supported on this system.");
        return false;
    }

    int attribs[40];
    int num_configs = 0;

    qt_format_to_attrib_list(f, attribs);

    GLXFBConfig *configs = glXChooseFBConfig(X11->display, X11->defaultScreen, attribs, &num_configs);
    if (configs && num_configs) {
        int res;
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_LEVEL, &res);
        format.setPlane(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_DOUBLEBUFFER, &res);
        format.setDoubleBuffer(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_DEPTH_SIZE, &res);
        format.setDepth(res);
        if (format.depth())
            format.setDepthBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_RGBA, &res);
        format.setRgba(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_RED_SIZE, &res);
        format.setRedBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_GREEN_SIZE, &res);
        format.setGreenBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_BLUE_SIZE, &res);
        format.setBlueBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_ALPHA_SIZE, &res);
        format.setAlpha(res);
        if (format.alpha())
            format.setAlphaBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_ACCUM_RED_SIZE, &res);
        format.setAccum(res);
        if (format.accum())
            format.setAccumBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_STENCIL_SIZE, &res);
        format.setStencil(res);
        if (format.stencil())
            format.setStencilBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_STEREO, &res);
        format.setStereo(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLE_BUFFERS_ARB, &res);
        format.setSampleBuffers(res);
        if (format.sampleBuffers()) {
            glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLES_ARB, &res);
            format.setSamples(res);
        }

        int pb_attribs[] = {GLX_PBUFFER_WIDTH, size.width(), GLX_PBUFFER_HEIGHT, size.height(), XNone};
        GLXContext shareContext = 0;
        if (shareWidget && shareWidget->d_func()->glcx)
            shareContext = (GLXContext) shareWidget->d_func()->glcx->d_func()->cx;

        pbuf = glXCreatePbuffer(QX11Info::display(), configs[0], pb_attribs);
        ctx = glXCreateNewContext(QX11Info::display(), configs[0], GLX_RGBA_TYPE, shareContext, true);

        XFree(configs);
        if (!pbuf || !ctx) {
            qWarning("QGLPixelBuffer: Unable to create a pbuffer/context - giving up.");
            return false;
        }
        return true;
    } else {
        qWarning("QGLPixelBuffer: Unable to find a context/format match - giving up.");
        return false;
    }
}

bool QGLPixelBufferPrivate::cleanup()
{
    glXDestroyPbuffer(QX11Info::display(), pbuf);
    return true;
}

bool QGLPixelBuffer::bindToDynamicTexture(GLuint)
{
    return false;
}

void QGLPixelBuffer::releaseFromDynamicTexture()
{
}

bool QGLPixelBuffer::hasOpenGLPbuffers()
{
    bool ret = qt_resolve_pbuffer_extensions();

    if (!ret)
	return false;

    int attribs[40];
    int num_configs = 0;

    qt_format_to_attrib_list(QGLFormat::defaultFormat(), attribs);

    GLXFBConfig *configs = glXChooseFBConfig(X11->display, X11->defaultScreen, attribs, &num_configs);
    GLXPbuffer pbuf = 0;
    GLXContext ctx = 0;

    if (configs && num_configs) {
        int pb_attribs[] = {GLX_PBUFFER_WIDTH, 128, GLX_PBUFFER_HEIGHT, 128, XNone};
        pbuf = glXCreatePbuffer(X11->display, configs[0], pb_attribs);
        ctx = glXCreateNewContext(X11->display, configs[0], GLX_RGBA_TYPE, 0, true);
        XFree(configs);
	glXDestroyContext(X11->display, ctx);
	glXDestroyPbuffer(X11->display, pbuf);
    }
    return pbuf && ctx;
}

QT_END_NAMESPACE
<commit_msg>Fixed usage of QGLPixelBuffer with share widgets on other X11 screens.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qlibrary.h>
#include <qdebug.h>
#include <private/qgl_p.h>
#include <private/qt_x11_p.h>
#include <private/qpaintengine_opengl_p.h>

#include <qx11info_x11.h>
#include <GL/glx.h>
#include <qimage.h>

#include "qglpixelbuffer.h"
#include "qglpixelbuffer_p.h"

#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
#include <dlfcn.h>
#endif

QT_BEGIN_NAMESPACE

#ifndef GLX_VERSION_1_3
#define GLX_RGBA_BIT            0x00000002
#define GLX_PBUFFER_BIT         0x00000004
#define GLX_DRAWABLE_TYPE       0x8010
#define GLX_RENDER_TYPE         0x8011
#define GLX_RGBA_TYPE           0x8014
#define GLX_PBUFFER_HEIGHT      0x8040
#define GLX_PBUFFER_WIDTH       0x8041
#endif

#ifndef GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB  100000
#define GLX_SAMPLES_ARB         100001
#endif

typedef GLXFBConfig* (*_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
typedef int (*_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
typedef GLXPbuffer (*_glXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attrib_list);
typedef void (*_glXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf);
typedef GLXContext (*_glXCreateNewContext) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
typedef Bool (*_glXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);

static _glXChooseFBConfig qt_glXChooseFBConfig = 0;
static _glXCreateNewContext qt_glXCreateNewContext = 0;
static _glXCreatePbuffer qt_glXCreatePbuffer = 0;
static _glXDestroyPbuffer qt_glXDestroyPbuffer = 0;
static _glXGetFBConfigAttrib qt_glXGetFBConfigAttrib = 0;
static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;

#define glXChooseFBConfig qt_glXChooseFBConfig
#define glXCreateNewContext qt_glXCreateNewContext
#define glXCreatePbuffer qt_glXCreatePbuffer
#define glXDestroyPbuffer qt_glXDestroyPbuffer
#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
#define glXMakeContextCurrent qt_glXMakeContextCurrent

extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp

static bool qt_resolve_pbuffer_extensions()
{
    static int resolved = false;
    if (resolved && qt_glXMakeContextCurrent)
        return true;
    else if (resolved)
        return false;

    qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig");
    qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext");
    qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer");
    qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer");
    qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib");
    qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent");

    resolved = qt_glXMakeContextCurrent ? true : false;
    return resolved;
}

static void qt_format_to_attrib_list(const QGLFormat &f, int attribs[])
{
    int i = 0;
    attribs[i++] = GLX_RENDER_TYPE;
    attribs[i++] = GLX_RGBA_BIT;
    attribs[i++] = GLX_DRAWABLE_TYPE;
    attribs[i++] = GLX_PBUFFER_BIT;
    attribs[i++] = GLX_RED_SIZE;
    attribs[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize();
    attribs[i++] = GLX_GREEN_SIZE;
    attribs[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize();
    attribs[i++] = GLX_BLUE_SIZE;
    attribs[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize();
    if (f.doubleBuffer()) {
        attribs[i++] = GLX_DOUBLEBUFFER;
        attribs[i++] = true;
    }
    if (f.depth()) {
        attribs[i++] = GLX_DEPTH_SIZE;
        attribs[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize();
    }
    if (f.stereo()) {
        attribs[i++] = GLX_STEREO;
        attribs[i++] = true;
    }
    if (f.stencil()) {
        attribs[i++] = GLX_STENCIL_SIZE;
        attribs[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize();
    }
    if (f.alpha()) {
        attribs[i++] = GLX_ALPHA_SIZE;
        attribs[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize();
    }
    if (f.accum()) {
        attribs[i++] = GLX_ACCUM_RED_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        attribs[i++] = GLX_ACCUM_GREEN_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        attribs[i++] = GLX_ACCUM_BLUE_SIZE;
        attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        if (f.alpha()) {
            attribs[i++] = GLX_ACCUM_ALPHA_SIZE;
            attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize();
        }
    }
    if (f.sampleBuffers()) {
        attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
        attribs[i++] = 1;
        attribs[i++] = GLX_SAMPLES_ARB;
        attribs[i++] = f.samples() == -1 ? 4 : f.samples();
    }

    attribs[i] = XNone;
}

bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget)
{
    if (!qt_resolve_pbuffer_extensions()) {
        qWarning("QGLPixelBuffer: pbuffers are not supported on this system.");
        return false;
    }

    int attribs[40];
    int num_configs = 0;

    qt_format_to_attrib_list(f, attribs);

    int screen = X11->defaultScreen;
    if (shareWidget)
        screen = shareWidget->x11Info().screen();

    GLXFBConfig *configs = glXChooseFBConfig(X11->display, screen, attribs, &num_configs);
    if (configs && num_configs) {
        int res;
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_LEVEL, &res);
        format.setPlane(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_DOUBLEBUFFER, &res);
        format.setDoubleBuffer(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_DEPTH_SIZE, &res);
        format.setDepth(res);
        if (format.depth())
            format.setDepthBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_RGBA, &res);
        format.setRgba(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_RED_SIZE, &res);
        format.setRedBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_GREEN_SIZE, &res);
        format.setGreenBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_BLUE_SIZE, &res);
        format.setBlueBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_ALPHA_SIZE, &res);
        format.setAlpha(res);
        if (format.alpha())
            format.setAlphaBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_ACCUM_RED_SIZE, &res);
        format.setAccum(res);
        if (format.accum())
            format.setAccumBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_STENCIL_SIZE, &res);
        format.setStencil(res);
        if (format.stencil())
            format.setStencilBufferSize(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_STEREO, &res);
        format.setStereo(res);
        glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLE_BUFFERS_ARB, &res);
        format.setSampleBuffers(res);
        if (format.sampleBuffers()) {
            glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLES_ARB, &res);
            format.setSamples(res);
        }

        int pb_attribs[] = {GLX_PBUFFER_WIDTH, size.width(), GLX_PBUFFER_HEIGHT, size.height(), XNone};
        GLXContext shareContext = 0;
        if (shareWidget && shareWidget->d_func()->glcx)
            shareContext = (GLXContext) shareWidget->d_func()->glcx->d_func()->cx;

        pbuf = glXCreatePbuffer(QX11Info::display(), configs[0], pb_attribs);
        ctx = glXCreateNewContext(QX11Info::display(), configs[0], GLX_RGBA_TYPE, shareContext, true);

        XFree(configs);
        if (!pbuf || !ctx) {
            qWarning("QGLPixelBuffer: Unable to create a pbuffer/context - giving up.");
            return false;
        }
        return true;
    } else {
        qWarning("QGLPixelBuffer: Unable to find a context/format match - giving up.");
        return false;
    }
}

bool QGLPixelBufferPrivate::cleanup()
{
    glXDestroyPbuffer(QX11Info::display(), pbuf);
    return true;
}

bool QGLPixelBuffer::bindToDynamicTexture(GLuint)
{
    return false;
}

void QGLPixelBuffer::releaseFromDynamicTexture()
{
}

bool QGLPixelBuffer::hasOpenGLPbuffers()
{
    bool ret = qt_resolve_pbuffer_extensions();

    if (!ret)
	return false;

    int attribs[40];
    int num_configs = 0;

    qt_format_to_attrib_list(QGLFormat::defaultFormat(), attribs);

    GLXFBConfig *configs = glXChooseFBConfig(X11->display, X11->defaultScreen, attribs, &num_configs);
    GLXPbuffer pbuf = 0;
    GLXContext ctx = 0;

    if (configs && num_configs) {
        int pb_attribs[] = {GLX_PBUFFER_WIDTH, 128, GLX_PBUFFER_HEIGHT, 128, XNone};
        pbuf = glXCreatePbuffer(X11->display, configs[0], pb_attribs);
        ctx = glXCreateNewContext(X11->display, configs[0], GLX_RGBA_TYPE, 0, true);
        XFree(configs);
	glXDestroyContext(X11->display, ctx);
	glXDestroyPbuffer(X11->display, pbuf);
    }
    return pbuf && ctx;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * 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 Software.
 *
 * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include "PerformanceCounterViewer.h"
#include "Windows/Dialogs/PerformanceCounterSelection.h"
#include "ui_PerformanceCounterViewer.h"

PerformanceCounterViewer::PerformanceCounterViewer(ICaptureContext &ctx, QWidget *parent)
    : QFrame(parent), ui(new Ui::PerformanceCounterViewer), m_Ctx(ctx)
{
  ui->setupUi(this);

  m_Ctx.AddLogViewer(this);

  connect(ui->captureCounters, &QToolButton::pressed, this,
          &PerformanceCounterViewer::CaptureCounters);

  ui->captureCounters->setEnabled(m_Ctx.LogLoaded());
}

PerformanceCounterViewer::~PerformanceCounterViewer()
{
  m_Ctx.BuiltinWindowClosed(this);

  m_Ctx.RemoveLogViewer(this);
  delete ui;
}

QString PerformanceCounterViewer::FormatCounterResult(const CounterResult &result,
                                                      const CounterDescription &description)
{
  QString returnValue;

  double mul = 1.0;

  TimeUnit timeunit = m_Ctx.Config().EventBrowser_TimeUnit;

  if(description.unit == CounterUnit::Seconds)
  {
    if(timeunit == TimeUnit::Milliseconds)
      mul *= 1000.0;
    else if(timeunit == TimeUnit::Microseconds)
      mul *= 1000000.0;
    else if(timeunit == TimeUnit::Nanoseconds)
      mul *= 1000000000.0;
  }

  switch(description.resultType)
  {
    case CompType::Float: returnValue += QString::number(mul * result.value.f); break;

    case CompType::Double: returnValue += QString::number(mul * result.value.d); break;

    case CompType::UInt:
      if(description.resultByteWidth == 8)
      {
        returnValue += QString::number(result.value.u64);
      }
      else
      {
        returnValue += QString::number(result.value.u32);
      }

    default:
      // assert (false)
      break;
  }

  switch(description.unit)
  {
    case CounterUnit::Bytes: returnValue += lit(" bytes"); break;

    case CounterUnit::Cycles: returnValue += lit(" cycles"); break;

    case CounterUnit::Percentage: returnValue += lit(" %"); break;

    case CounterUnit::Seconds: returnValue += lit(" ") + UnitSuffix(timeunit); break;

    case CounterUnit::Absolute:
    case CounterUnit::Ratio: break;
  }

  return returnValue;
}

void PerformanceCounterViewer::CaptureCounters()
{
  if(!m_Ctx.LogLoaded())
    return;

  PerformanceCounterSelection pcs(m_Ctx, this);
  if(RDDialog::show(&pcs) != QDialog::Accepted)
    return;
  const QList<GPUCounter> selectedCounters = pcs.GetSelectedCounters();

  bool done = false;
  m_Ctx.Replay().AsyncInvoke([this, selectedCounters, &done](IReplayController *controller) -> void {
    rdctype::array<GPUCounter> counters;
    counters.create(selectedCounters.size());

    QMap<GPUCounter, CounterDescription> counterDescriptions;

    for(int i = 0; i < selectedCounters.size(); ++i)
    {
      counters[i] = (GPUCounter)selectedCounters[i];
      counterDescriptions.insert(counters[i], controller->DescribeCounter(counters[i]));
    }

    QMap<GPUCounter, int> counterIndex;
    for(int i = 0; i < selectedCounters.size(); ++i)
    {
      counterIndex.insert((GPUCounter)selectedCounters[i], i);
    }

    const rdctype::array<CounterResult> results = controller->FetchCounters(counters);

    GUIInvoke::call([this, results, counterDescriptions, counterIndex]() -> void {
      ui->counterResults->clear();

      QStringList headers;
      headers << lit("EID");
      for(const CounterDescription &cd : counterDescriptions)
      {
        headers << cd.name;
      }

      QMap<uint32_t, int> eventIdToRow;
      for(const CounterResult &result : results)
      {
        if(eventIdToRow.contains(result.eventID))
          continue;
        eventIdToRow[result.eventID] = eventIdToRow.size();
      }

      ui->counterResults->setColumnCount(headers.size());
      ui->counterResults->setHorizontalHeaderLabels(headers);
      ui->counterResults->setRowCount(eventIdToRow.size());

      for(int i = 0; i < (int)results.size(); ++i)
      {
        int row = eventIdToRow[results[i].eventID];
        ui->counterResults->setItem(row, 0,
                                    new QTableWidgetItem(QString::number(results[i].eventID)));
        ui->counterResults->setItem(row, counterIndex[results[i].counterID] + 1,
                                    new QTableWidgetItem(FormatCounterResult(
                                        results[i], counterDescriptions[results[i].counterID])));

        ui->counterResults->item(row, 0)->setData(Qt::UserRole, results[i].eventID);
      }

      ui->counterResults->resizeColumnsToContents();
    });

    done = true;
  });

  ShowProgressDialog(this, tr("Capturing counters"), [&done]() -> bool { return done; });
}

void PerformanceCounterViewer::OnLogfileClosed()
{
  ui->captureCounters->setEnabled(false);
}

void PerformanceCounterViewer::OnLogfileLoaded()
{
  ui->captureCounters->setEnabled(true);
}

void PerformanceCounterViewer::on_counterResults_doubleClicked(const QModelIndex &index)
{
  QTableWidgetItem *item = ui->counterResults->item(index.row(), 0);

  if(item)
  {
    bool ok = false;
    uint32_t eid = item->data(Qt::UserRole).toUInt(&ok);

    if(ok)
      m_Ctx.SetEventID({}, eid, eid);
  }
}
<commit_msg>Use Formatter for float-formatting preferences<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * 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 Software.
 *
 * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include "PerformanceCounterViewer.h"
#include "Windows/Dialogs/PerformanceCounterSelection.h"
#include "ui_PerformanceCounterViewer.h"

PerformanceCounterViewer::PerformanceCounterViewer(ICaptureContext &ctx, QWidget *parent)
    : QFrame(parent), ui(new Ui::PerformanceCounterViewer), m_Ctx(ctx)
{
  ui->setupUi(this);

  m_Ctx.AddLogViewer(this);

  connect(ui->captureCounters, &QToolButton::pressed, this,
          &PerformanceCounterViewer::CaptureCounters);

  ui->captureCounters->setEnabled(m_Ctx.LogLoaded());
}

PerformanceCounterViewer::~PerformanceCounterViewer()
{
  m_Ctx.BuiltinWindowClosed(this);

  m_Ctx.RemoveLogViewer(this);
  delete ui;
}

QString PerformanceCounterViewer::FormatCounterResult(const CounterResult &result,
                                                      const CounterDescription &description)
{
  QString returnValue;

  double mul = 1.0;

  TimeUnit timeunit = m_Ctx.Config().EventBrowser_TimeUnit;

  if(description.unit == CounterUnit::Seconds)
  {
    if(timeunit == TimeUnit::Milliseconds)
      mul *= 1000.0;
    else if(timeunit == TimeUnit::Microseconds)
      mul *= 1000000.0;
    else if(timeunit == TimeUnit::Nanoseconds)
      mul *= 1000000000.0;
  }

  switch(description.resultType)
  {
    case CompType::Float: returnValue += Formatter::Format(mul * result.value.f); break;

    case CompType::Double: returnValue += Formatter::Format(mul * result.value.d); break;

    case CompType::UInt:
      if(description.resultByteWidth == 8)
      {
        returnValue += Formatter::Format(result.value.u64);
      }
      else
      {
        returnValue += Formatter::Format(result.value.u32);
      }

    default:
      // assert (false)
      break;
  }

  switch(description.unit)
  {
    case CounterUnit::Bytes: returnValue += lit(" bytes"); break;

    case CounterUnit::Cycles: returnValue += lit(" cycles"); break;

    case CounterUnit::Percentage: returnValue += lit(" %"); break;

    case CounterUnit::Seconds: returnValue += lit(" ") + UnitSuffix(timeunit); break;

    case CounterUnit::Absolute:
    case CounterUnit::Ratio: break;
  }

  return returnValue;
}

void PerformanceCounterViewer::CaptureCounters()
{
  if(!m_Ctx.LogLoaded())
    return;

  PerformanceCounterSelection pcs(m_Ctx, this);
  if(RDDialog::show(&pcs) != QDialog::Accepted)
    return;
  const QList<GPUCounter> selectedCounters = pcs.GetSelectedCounters();

  bool done = false;
  m_Ctx.Replay().AsyncInvoke([this, selectedCounters, &done](IReplayController *controller) -> void {
    rdctype::array<GPUCounter> counters;
    counters.create(selectedCounters.size());

    QMap<GPUCounter, CounterDescription> counterDescriptions;

    for(int i = 0; i < selectedCounters.size(); ++i)
    {
      counters[i] = (GPUCounter)selectedCounters[i];
      counterDescriptions.insert(counters[i], controller->DescribeCounter(counters[i]));
    }

    QMap<GPUCounter, int> counterIndex;
    for(int i = 0; i < selectedCounters.size(); ++i)
    {
      counterIndex.insert((GPUCounter)selectedCounters[i], i);
    }

    const rdctype::array<CounterResult> results = controller->FetchCounters(counters);

    GUIInvoke::call([this, results, counterDescriptions, counterIndex]() -> void {
      ui->counterResults->clear();

      QStringList headers;
      headers << lit("EID");
      for(const CounterDescription &cd : counterDescriptions)
      {
        headers << cd.name;
      }

      QMap<uint32_t, int> eventIdToRow;
      for(const CounterResult &result : results)
      {
        if(eventIdToRow.contains(result.eventID))
          continue;
        eventIdToRow[result.eventID] = eventIdToRow.size();
      }

      ui->counterResults->setColumnCount(headers.size());
      ui->counterResults->setHorizontalHeaderLabels(headers);
      ui->counterResults->setRowCount(eventIdToRow.size());

      for(int i = 0; i < (int)results.size(); ++i)
      {
        int row = eventIdToRow[results[i].eventID];
        ui->counterResults->setItem(row, 0,
                                    new QTableWidgetItem(QString::number(results[i].eventID)));
        ui->counterResults->setItem(row, counterIndex[results[i].counterID] + 1,
                                    new QTableWidgetItem(FormatCounterResult(
                                        results[i], counterDescriptions[results[i].counterID])));

        ui->counterResults->item(row, 0)->setData(Qt::UserRole, results[i].eventID);
      }

      ui->counterResults->resizeColumnsToContents();
    });

    done = true;
  });

  ShowProgressDialog(this, tr("Capturing counters"), [&done]() -> bool { return done; });
}

void PerformanceCounterViewer::OnLogfileClosed()
{
  ui->captureCounters->setEnabled(false);
}

void PerformanceCounterViewer::OnLogfileLoaded()
{
  ui->captureCounters->setEnabled(true);
}

void PerformanceCounterViewer::on_counterResults_doubleClicked(const QModelIndex &index)
{
  QTableWidgetItem *item = ui->counterResults->item(index.row(), 0);

  if(item)
  {
    bool ok = false;
    uint32_t eid = item->data(Qt::UserRole).toUInt(&ok);

    if(ok)
      m_Ctx.SetEventID({}, eid, eid);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Actions/Draw.hpp>
#include <hspp/Cards/Cards.hpp>
#include <hspp/Games/Game.hpp>
#include <hspp/Games/GameManager.hpp>

#include <effolkronium/random.hpp>

#include <algorithm>

using Random = effolkronium::random_static;

namespace Hearthstonepp
{
Game::Game(GameConfig& gameConfig) : m_gameConfig(gameConfig)
{
    // Add hero and hero power
    GetPlayer1().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player1Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player1Class));
    GetPlayer2().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player2Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player2Class));

    // Set opponent player
    GetPlayer1().SetOpponent(&GetPlayer2());
    GetPlayer2().SetOpponent(&GetPlayer1());
}

Player& Game::GetPlayer1()
{
    return m_players[0];
}

Player& Game::GetPlayer2()
{
    return m_players[1];
}

Player& Game::GetCurrentPlayer()
{
    return *m_currentPlayer;
}

Player& Game::GetOpponentPlayer()
{
    return m_currentPlayer->GetOpponent();
}

void Game::BeginFirst()
{
    // Set next step
    nextStep = Step::BEGIN_SHUFFLE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginShuffle()
{
    // Shuffle cards in deck
    if (m_gameConfig.doShuffle)
    {
        GetPlayer1().GetDeck().Shuffle();
        GetPlayer2().GetDeck().Shuffle();
    }

    // Set next step
    nextStep = Step::BEGIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginDraw()
{
    for (auto& p : m_players)
    {
        // Draw 3 cards
        Generic::Draw(p);
        Generic::Draw(p);
        Generic::Draw(p);

        if (&p != m_firstPlayer)
        {
            // Draw 4th card for second player
            Generic::Draw(p);

            // Give "The Coin" card to second player
            Card coin = Cards::GetInstance().FindCardByID("GAME_005");
            p.GetHand().AddCard(*Entity::GetFromCard(p, std::move(coin)));
        }
    }

    // Set next step
    nextStep =
        m_gameConfig.skipMulligan ? Step::MAIN_BEGIN : Step::BEGIN_MULLIGAN;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginMulligan()
{
    // Do nothing
}

void Game::MainBegin()
{
    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainReady()
{
    // Reset the number of attacked
    for (auto& p : m_players)
    {
        // Hero
        p.GetHero()->numAttacked = 0;
        // Field
        for (auto& m : p.GetField().GetAllMinions())
        {
            m->numAttacked = 0;
        }
    }

    // Reset exhaust for current player
    auto& curPlayer = GetCurrentPlayer();
    // Hero
    curPlayer.GetHero()->SetGameTag(GameTag::EXHAUSTED, 0);
    // Weapon
    if (curPlayer.GetHero()->weapon != nullptr)
    {
        curPlayer.GetHero()->weapon->SetGameTag(GameTag::EXHAUSTED, 0);
    }
    // Hero power
    curPlayer.GetHero()->heroPower->SetGameTag(GameTag::EXHAUSTED, 0);
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        m->SetGameTag(GameTag::EXHAUSTED, 0);
    }

    // Set next step
    nextStep = Step::MAIN_START_TRIGGERS;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStartTriggers()
{
    // Set next step
    nextStep = Step::MAIN_RESOURCE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainResource()
{
    // Do nothing
}

void Game::MainDraw()
{
    // Do nothing
}

void Game::MainStart()
{
    // Do nothing
}

void Game::MainAction()
{
    // Do nothing
}

void Game::MainCombat()
{
    // Do nothing
}

void Game::MainEnd()
{
    // Do nothing
}

void Game::MainCleanUp()
{
    // Do nothing
}

void Game::MainNext()
{
    // Do nothing
}

void Game::FinalWrapUp()
{
    // Do nothing
}

void Game::FinalGameOver()
{
    // Do nothing
}

void Game::StartGame()
{
    // Reverse card order in deck
    if (!m_gameConfig.doShuffle)
    {
        std::reverse(m_gameConfig.player1Deck.begin(),
                     m_gameConfig.player1Deck.end());
        std::reverse(m_gameConfig.player2Deck.begin(),
                     m_gameConfig.player2Deck.end());
    }

    // Set up decks
    for (auto& card : m_gameConfig.player1Deck)
    {
        Entity* entity = Entity::GetFromCard(GetPlayer1(), std::move(card));
        GetPlayer1().GetDeck().AddCard(*entity);
    }
    for (auto& card : m_gameConfig.player2Deck)
    {
        Entity* entity = Entity::GetFromCard(GetPlayer2(), std::move(card));
        GetPlayer2().GetDeck().AddCard(*entity);
    }

    // Determine first player
    switch (m_gameConfig.startPlayer)
    {
        case PlayerType::RANDOM:
        {
            auto val = Random::get(0, 1);
            m_firstPlayer = &m_players[val];
            break;
        }
        case PlayerType::PLAYER1:
            m_firstPlayer = &m_players[0];
            break;
        case PlayerType::PLAYER2:
            m_firstPlayer = &m_players[1];
            break;
    }
    m_currentPlayer = m_firstPlayer;

    // Set first turn
    m_turn = 1;

    // Set next step
    nextStep = Step::BEGIN_FIRST;
    GameManager::ProcessNextStep(*this, nextStep);
}
}  // namespace Hearthstonepp<commit_msg>[ci skip] feat(game-state): Add code to add mana crystal to cur player<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Actions/Draw.hpp>
#include <hspp/Actions/Generic.hpp>
#include <hspp/Cards/Cards.hpp>
#include <hspp/Games/Game.hpp>
#include <hspp/Games/GameManager.hpp>

#include <effolkronium/random.hpp>

#include <algorithm>

using Random = effolkronium::random_static;

namespace Hearthstonepp
{
Game::Game(GameConfig& gameConfig) : m_gameConfig(gameConfig)
{
    // Add hero and hero power
    GetPlayer1().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player1Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player1Class));
    GetPlayer2().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player2Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player2Class));

    // Set opponent player
    GetPlayer1().SetOpponent(&GetPlayer2());
    GetPlayer2().SetOpponent(&GetPlayer1());
}

Player& Game::GetPlayer1()
{
    return m_players[0];
}

Player& Game::GetPlayer2()
{
    return m_players[1];
}

Player& Game::GetCurrentPlayer()
{
    return *m_currentPlayer;
}

Player& Game::GetOpponentPlayer()
{
    return m_currentPlayer->GetOpponent();
}

void Game::BeginFirst()
{
    // Set next step
    nextStep = Step::BEGIN_SHUFFLE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginShuffle()
{
    // Shuffle cards in deck
    if (m_gameConfig.doShuffle)
    {
        GetPlayer1().GetDeck().Shuffle();
        GetPlayer2().GetDeck().Shuffle();
    }

    // Set next step
    nextStep = Step::BEGIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginDraw()
{
    for (auto& p : m_players)
    {
        // Draw 3 cards
        Generic::Draw(p);
        Generic::Draw(p);
        Generic::Draw(p);

        if (&p != m_firstPlayer)
        {
            // Draw 4th card for second player
            Generic::Draw(p);

            // Give "The Coin" card to second player
            Card coin = Cards::GetInstance().FindCardByID("GAME_005");
            p.GetHand().AddCard(*Entity::GetFromCard(p, std::move(coin)));
        }
    }

    // Set next step
    nextStep =
        m_gameConfig.skipMulligan ? Step::MAIN_BEGIN : Step::BEGIN_MULLIGAN;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginMulligan()
{
    // Do nothing
}

void Game::MainBegin()
{
    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainReady()
{
    // Reset the number of attacked
    for (auto& p : m_players)
    {
        // Hero
        p.GetHero()->numAttacked = 0;
        // Field
        for (auto& m : p.GetField().GetAllMinions())
        {
            m->numAttacked = 0;
        }
    }

    // Reset exhaust for current player
    auto& curPlayer = GetCurrentPlayer();
    // Hero
    curPlayer.GetHero()->SetGameTag(GameTag::EXHAUSTED, 0);
    // Weapon
    if (curPlayer.GetHero()->weapon != nullptr)
    {
        curPlayer.GetHero()->weapon->SetGameTag(GameTag::EXHAUSTED, 0);
    }
    // Hero power
    curPlayer.GetHero()->heroPower->SetGameTag(GameTag::EXHAUSTED, 0);
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        m->SetGameTag(GameTag::EXHAUSTED, 0);
    }

    // Set next step
    nextStep = Step::MAIN_START_TRIGGERS;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStartTriggers()
{
    // Set next step
    nextStep = Step::MAIN_RESOURCE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainResource()
{
    auto& curPlayer = GetCurrentPlayer();

    // Add mana crystal to current player
    Generic::ChangeManaCrystal(curPlayer, 1, false);
}

void Game::MainDraw()
{
    // Do nothing
}

void Game::MainStart()
{
    // Do nothing
}

void Game::MainAction()
{
    // Do nothing
}

void Game::MainCombat()
{
    // Do nothing
}

void Game::MainEnd()
{
    // Do nothing
}

void Game::MainCleanUp()
{
    // Do nothing
}

void Game::MainNext()
{
    // Do nothing
}

void Game::FinalWrapUp()
{
    // Do nothing
}

void Game::FinalGameOver()
{
    // Do nothing
}

void Game::StartGame()
{
    // Reverse card order in deck
    if (!m_gameConfig.doShuffle)
    {
        std::reverse(m_gameConfig.player1Deck.begin(),
                     m_gameConfig.player1Deck.end());
        std::reverse(m_gameConfig.player2Deck.begin(),
                     m_gameConfig.player2Deck.end());
    }

    // Set up decks
    for (auto& card : m_gameConfig.player1Deck)
    {
        Entity* entity = Entity::GetFromCard(GetPlayer1(), std::move(card));
        GetPlayer1().GetDeck().AddCard(*entity);
    }
    for (auto& card : m_gameConfig.player2Deck)
    {
        Entity* entity = Entity::GetFromCard(GetPlayer2(), std::move(card));
        GetPlayer2().GetDeck().AddCard(*entity);
    }

    // Determine first player
    switch (m_gameConfig.startPlayer)
    {
        case PlayerType::RANDOM:
        {
            auto val = Random::get(0, 1);
            m_firstPlayer = &m_players[val];
            break;
        }
        case PlayerType::PLAYER1:
            m_firstPlayer = &m_players[0];
            break;
        case PlayerType::PLAYER2:
            m_firstPlayer = &m_players[1];
            break;
    }
    m_currentPlayer = m_firstPlayer;

    // Set first turn
    m_turn = 1;

    // Set next step
    nextStep = Step::BEGIN_FIRST;
    GameManager::ProcessNextStep(*this, nextStep);
}
}  // namespace Hearthstonepp<|endoftext|>