<commit_before>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <stdexcept>

#include "util/FileHelper.h"
#include "util/stringhelper.h"
#include "ManifestLoaderv1.h"
#include "util/JpegHelper.h"

#include "DeepCLDllExport.h"

using namespace std;

#undef STATIC
#undef VIRTUAL
#define STATIC
#define VIRTUAL

PUBLIC STATIC bool ManifestLoaderv1::isFormatFor(std::string imagesFilepath) {
    cout << "ManifestLoaderv1 checking format for " << imagesFilepath << endl;
    string sigString = "# format=deepcl-jpeg-list-v1 ";
    char *headerBytes = FileHelper::readBinaryChunk(imagesFilepath, 0, sigString.length() + 1);
    headerBytes[sigString.length()] = 0;
    bool matched = string(headerBytes) == sigString;
    cout << "matched: " << matched << endl;
    return matched;
}
PUBLIC ManifestLoaderv1::ManifestLoaderv1(std::string imagesFilepath) {
    init(imagesFilepath);
}
PRIVATE void ManifestLoaderv1::init(std::string imagesFilepath) {
    this->imagesFilepath = imagesFilepath;
    // by reading the number of lines in the manifest, we can get the number of examples, *p_N
    // number of planes is .... 1
    // imageSize is ...

    if(!isFormatFor(imagesFilepath) ) {
        throw runtime_error("file " + imagesFilepath + " is not a deepcl-jpeg-list-v1 manifest file");
    }

    ifstream infile(imagesFilepath);
    char lineChars[1024];
    infile.getline(lineChars, 1024); // skip first, header, line
    string firstLine = string(lineChars);
//    cout << "firstline: [" << firstLine << "]" << endl;
    vector<string> splitLine = split(firstLine, " ");
    N = readIntValue(splitLine, "N");
    planes = readIntValue(splitLine, "planes");
    size = readIntValue(splitLine, "width");
    int imageSizeRepeated = readIntValue(splitLine, "height");
    if(size != imageSizeRepeated) {
        throw runtime_error("file " + imagesFilepath + " contains non-square images.  Not handled for now.");
    }
    // now we should load into memory, since the file is not fixed-size records, and cannot be loaded partially easily

    files = new string[N];
    labels = 0;

    int n = 0;
    hasLabels = false;
    while(infile) {
        infile.getline(lineChars, 1024);
        if(!infile) {
            break;
        }
        string line = string(lineChars);
        if(line == "") {
            continue;
        }
        vector<string> splitLine = split(line, " ");
        if((int)splitLine.size() == 0) {
            continue;
        }
        if(n == 0) {
            int lineSize = (int)splitLine.size();
            if(lineSize == 2) {
                hasLabels = true;
                labels = new int[N];
            }
        }
        if(!hasLabels && (int)splitLine.size() != 1) {
            throw runtime_error("Error reading " + imagesFilepath + ".  Following line not parseable:\n" + line);
        }
        if(hasLabels && (int)splitLine.size() != 2) {
            throw runtime_error("Error reading " + imagesFilepath + ".  Following line not parseable:\n" + line);
        }
        string jpegFile = splitLine[0];
        #ifdef _WIN32
        if(jpegFile[1] != ':' && jpegFile[0] != '\\') {  // I guess this means its a relative path?
            vector<string> splitManifestPath = split(imagesFilepath, "\\");
            string dirPath = replace(imagesFilepath, splitManifestPath[splitManifestPath.size()-1], "");
            jpegFile = dirPath + jpegFile;
        }
        #else
        if(jpegFile[0] != '/') {  // this is a bit hacky, but at least handles linux and mac for now...
            vector<string> splitManifestPath = split(imagesFilepath, "/");
            string dirPath = replace(imagesFilepath, splitManifestPath[splitManifestPath.size()-1], "");
            jpegFile = dirPath + jpegFile;
        }
        #endif
        files[n] = jpegFile;
        if(hasLabels) {
            int label = atoi(splitLine[1]);
            labels[n] = label;
        }
//        cout << "file " << jpegFile << " label=" << label << endl;
        n++;
    }
    infile.close();
    if(n != N) {
        throw runtime_error("Error: number of images declared in manifest " + toString(N) + " doesnt match number actually in manifest " + to_string(n));
    }

    cout << "manifest " << imagesFilepath << " read. N=" << N << " planes=" << planes << " size=" << size << " labels? " << hasLabels << endl;
}
PUBLIC VIRTUAL std::string ManifestLoaderv1::getType() {
    return "ManifestLoaderv1";
}
PUBLIC VIRTUAL int ManifestLoaderv1::getImageCubeSize() {
    return planes * size * size;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getN() {
    return N;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getPlanes() {
    return planes;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getImageSize() {
    return size;
}
int ManifestLoaderv1::readIntValue(std::vector< std::string > splitLine, std::string key) {
    for(int i = 0; i < (int)splitLine.size(); i++) {
        vector<string> splitPair = split(splitLine[i], "=");
        if((int)splitPair.size() == 2) {
            if(splitPair[0] == key) {
                return atoi(splitPair[1]);
            }
        }
    }
    throw runtime_error("Key " + key + " not found in file header");
}
PUBLIC VIRTUAL void ManifestLoaderv1::load(unsigned char *data, int *labels, int startRecord, int numRecords) {
    int imageCubeSize = planes * size * size;
//    cout << "ManifestLoaderv1, loading " << numRecords << " jpegs" << endl;
    for(int localN = 0; localN < numRecords; localN++) {
        int globalN = localN + startRecord;
        if(globalN >= N) {
            return;
        }
        JpegHelper::read(files[globalN], planes, size, size, data + localN * imageCubeSize);
        if(labels != 0) {
            if(!hasLabels) {
                throw runtime_error("ManifestLoaderv1: labels reqested in load() method, but none found in file");
            }
            labels[localN] = this->labels[globalN];
        }
    }
}

<commit_msg>another tostring<commit_after>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <stdexcept>

#include "util/FileHelper.h"
#include "util/stringhelper.h"
#include "ManifestLoaderv1.h"
#include "util/JpegHelper.h"

#include "DeepCLDllExport.h"

using namespace std;

#undef STATIC
#undef VIRTUAL
#define STATIC
#define VIRTUAL

PUBLIC STATIC bool ManifestLoaderv1::isFormatFor(std::string imagesFilepath) {
    cout << "ManifestLoaderv1 checking format for " << imagesFilepath << endl;
    string sigString = "# format=deepcl-jpeg-list-v1 ";
    char *headerBytes = FileHelper::readBinaryChunk(imagesFilepath, 0, sigString.length() + 1);
    headerBytes[sigString.length()] = 0;
    bool matched = string(headerBytes) == sigString;
    cout << "matched: " << matched << endl;
    return matched;
}
PUBLIC ManifestLoaderv1::ManifestLoaderv1(std::string imagesFilepath) {
    init(imagesFilepath);
}
PRIVATE void ManifestLoaderv1::init(std::string imagesFilepath) {
    this->imagesFilepath = imagesFilepath;
    // by reading the number of lines in the manifest, we can get the number of examples, *p_N
    // number of planes is .... 1
    // imageSize is ...

    if(!isFormatFor(imagesFilepath) ) {
        throw runtime_error("file " + imagesFilepath + " is not a deepcl-jpeg-list-v1 manifest file");
    }

    ifstream infile(imagesFilepath);
    char lineChars[1024];
    infile.getline(lineChars, 1024); // skip first, header, line
    string firstLine = string(lineChars);
//    cout << "firstline: [" << firstLine << "]" << endl;
    vector<string> splitLine = split(firstLine, " ");
    N = readIntValue(splitLine, "N");
    planes = readIntValue(splitLine, "planes");
    size = readIntValue(splitLine, "width");
    int imageSizeRepeated = readIntValue(splitLine, "height");
    if(size != imageSizeRepeated) {
        throw runtime_error("file " + imagesFilepath + " contains non-square images.  Not handled for now.");
    }
    // now we should load into memory, since the file is not fixed-size records, and cannot be loaded partially easily

    files = new string[N];
    labels = 0;

    int n = 0;
    hasLabels = false;
    while(infile) {
        infile.getline(lineChars, 1024);
        if(!infile) {
            break;
        }
        string line = string(lineChars);
        if(line == "") {
            continue;
        }
        vector<string> splitLine = split(line, " ");
        if((int)splitLine.size() == 0) {
            continue;
        }
        if(n == 0) {
            int lineSize = (int)splitLine.size();
            if(lineSize == 2) {
                hasLabels = true;
                labels = new int[N];
            }
        }
        if(!hasLabels && (int)splitLine.size() != 1) {
            throw runtime_error("Error reading " + imagesFilepath + ".  Following line not parseable:\n" + line);
        }
        if(hasLabels && (int)splitLine.size() != 2) {
            throw runtime_error("Error reading " + imagesFilepath + ".  Following line not parseable:\n" + line);
        }
        string jpegFile = splitLine[0];
        #ifdef _WIN32
        if(jpegFile[1] != ':' && jpegFile[0] != '\\') {  // I guess this means its a relative path?
            vector<string> splitManifestPath = split(imagesFilepath, "\\");
            string dirPath = replace(imagesFilepath, splitManifestPath[splitManifestPath.size()-1], "");
            jpegFile = dirPath + jpegFile;
        }
        #else
        if(jpegFile[0] != '/') {  // this is a bit hacky, but at least handles linux and mac for now...
            vector<string> splitManifestPath = split(imagesFilepath, "/");
            string dirPath = replace(imagesFilepath, splitManifestPath[splitManifestPath.size()-1], "");
            jpegFile = dirPath + jpegFile;
        }
        #endif
        files[n] = jpegFile;
        if(hasLabels) {
            int label = atoi(splitLine[1]);
            labels[n] = label;
        }
//        cout << "file " << jpegFile << " label=" << label << endl;
        n++;
    }
    infile.close();
    if(n != N) {
        throw runtime_error("Error: number of images declared in manifest " + toString(N) + " doesnt match number actually in manifest " + toString(n));
    }

    cout << "manifest " << imagesFilepath << " read. N=" << N << " planes=" << planes << " size=" << size << " labels? " << hasLabels << endl;
}
PUBLIC VIRTUAL std::string ManifestLoaderv1::getType() {
    return "ManifestLoaderv1";
}
PUBLIC VIRTUAL int ManifestLoaderv1::getImageCubeSize() {
    return planes * size * size;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getN() {
    return N;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getPlanes() {
    return planes;
}
PUBLIC VIRTUAL int ManifestLoaderv1::getImageSize() {
    return size;
}
int ManifestLoaderv1::readIntValue(std::vector< std::string > splitLine, std::string key) {
    for(int i = 0; i < (int)splitLine.size(); i++) {
        vector<string> splitPair = split(splitLine[i], "=");
        if((int)splitPair.size() == 2) {
            if(splitPair[0] == key) {
                return atoi(splitPair[1]);
            }
        }
    }
    throw runtime_error("Key " + key + " not found in file header");
}
PUBLIC VIRTUAL void ManifestLoaderv1::load(unsigned char *data, int *labels, int startRecord, int numRecords) {
    int imageCubeSize = planes * size * size;
//    cout << "ManifestLoaderv1, loading " << numRecords << " jpegs" << endl;
    for(int localN = 0; localN < numRecords; localN++) {
        int globalN = localN + startRecord;
        if(globalN >= N) {
            return;
        }
        JpegHelper::read(files[globalN], planes, size, size, data + localN * imageCubeSize);
        if(labels != 0) {
            if(!hasLabels) {
                throw runtime_error("ManifestLoaderv1: labels reqested in load() method, but none found in file");
            }
            labels[localN] = this->labels[globalN];
        }
    }
}

<|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 "content/browser/renderer_host/gesture_event_filter.h"

#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/tap_suppression_controller.h"
#include "content/public/common/content_switches.h"

using WebKit::WebGestureEvent;
using WebKit::WebInputEvent;

namespace content {
namespace {

// Default maximum time between the GestureRecognizer generating a
// GestureTapDown and when it is forwarded to the renderer.
static const int kTapDownDeferralTimeMs = 150;

// Default debouncing interval duration: if a scroll is in progress, non-scroll
// events during this interval are deferred to either its end or discarded on
// receipt of another GestureScrollUpdate.
static const int kDebouncingIntervalTimeMs = 30;

// Sets |*value| to |switchKey| if it exists or sets it to |defaultValue|.
static void GetParamHelper(int* value,
                           int defaultValue,
                           const char switchKey[]) {
  if (*value < 0) {
    *value = defaultValue;
    CommandLine* command_line = CommandLine::ForCurrentProcess();
    std::string command_line_param =
        command_line->GetSwitchValueASCII(switchKey);
    if (!command_line_param.empty()) {
      int v;
      if (base::StringToInt(command_line_param, &v))
        *value = v;
    }
    DCHECK_GE(*value, 0);
  }
}

static int GetTapDownDeferralTimeMs() {
  static int tap_down_deferral_time_window = -1;
  GetParamHelper(&tap_down_deferral_time_window,
                 kTapDownDeferralTimeMs,
                 switches::kTapDownDeferralTimeMs);
  return tap_down_deferral_time_window;
}
} // namespace

GestureEventFilter::GestureEventFilter(RenderWidgetHostImpl* rwhv)
     : render_widget_host_(rwhv),
       fling_in_progress_(false),
       scrolling_in_progress_(false),
       tap_suppression_controller_(new TapSuppressionController(rwhv)),
       maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()),
       debounce_interval_time_ms_(kDebouncingIntervalTimeMs) {
}

GestureEventFilter::~GestureEventFilter() { }

bool GestureEventFilter::ShouldDiscardFlingCancelEvent(
    const WebKit::WebGestureEvent& gesture_event) {
  if (coalesced_gesture_events_.empty() && fling_in_progress_)
    return false;
  GestureEventQueue::reverse_iterator it =
      coalesced_gesture_events_.rbegin();
  while (it != coalesced_gesture_events_.rend()) {
    if (it->type == WebInputEvent::GestureFlingStart)
      return false;
    if (it->type == WebInputEvent::GestureFlingCancel)
      return true;
    it++;
  }
  return true;
}

bool GestureEventFilter::ShouldForwardForBounceReduction(
    const WebGestureEvent& gesture_event) {
  switch (gesture_event.type) {
    case WebInputEvent::GestureScrollUpdate:
      if (!scrolling_in_progress_) {
        debounce_deferring_timer_.Start(FROM_HERE,
              base::TimeDelta::FromMilliseconds(debounce_interval_time_ms_),
              this,
              &GestureEventFilter::SendScrollEndingEventsNow);
      } else {
        // Extend the bounce interval.
        debounce_deferring_timer_.Reset();
      }
      scrolling_in_progress_ = true;
      debouncing_deferral_queue_.clear();
      return true;
    case WebInputEvent::GesturePinchBegin:
      // TODO(rjkroege): Debounce pinch (http://crbug.com/147647)
      scrolling_in_progress_ = false;
      return true;
    default:
      if (scrolling_in_progress_) {
        debouncing_deferral_queue_.push_back(gesture_event);
        return false;
      }
      return true;
  }

  NOTREACHED();
  return false;
}

// NOTE: The filters are applied successively. This simplifies the change.
bool GestureEventFilter::ShouldForward(const WebGestureEvent& gesture_event) {
  if (debounce_interval_time_ms_ ==  0 ||
      ShouldForwardForBounceReduction(gesture_event))
    return ShouldForwardForTapDeferral(gesture_event);
  return false;
}

// TODO(rjkroege): separate touchpad and touchscreen events.
bool GestureEventFilter::ShouldForwardForTapDeferral(
    const WebGestureEvent& gesture_event) {
  switch (gesture_event.type) {
    case WebInputEvent::GestureFlingCancel:
      if (!ShouldDiscardFlingCancelEvent(gesture_event)) {
        coalesced_gesture_events_.push_back(gesture_event);
        fling_in_progress_ = false;
        return ShouldHandleEventNow();
      }
      return false;
    case WebInputEvent::GestureFlingStart:
      fling_in_progress_ = true;
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureTapDown:
      // GestureTapDown is always paired with either a Tap or TapCancel, so
      // it should be impossible to have more than one outstanding at a time.
      DCHECK_EQ(deferred_tap_down_event_.type, WebInputEvent::Undefined);
      deferred_tap_down_event_ = gesture_event;
      send_gtd_timer_.Start(FROM_HERE,
          base::TimeDelta::FromMilliseconds(maximum_tap_gap_time_ms_),
          this,
          &GestureEventFilter::SendGestureTapDownNow);
      return false;
    case WebInputEvent::GestureTapCancel:
      if (deferred_tap_down_event_.type == WebInputEvent::Undefined) {
        // The TapDown has already been put in the queue, must send the
        // corresponding TapCancel as well.
        coalesced_gesture_events_.push_back(gesture_event);
        return ShouldHandleEventNow();
      }
      // Cancelling a deferred TapDown, just drop them on the floor.
      send_gtd_timer_.Stop();
      deferred_tap_down_event_.type = WebInputEvent::Undefined;
      return false;
    case WebInputEvent::GestureTap:
      send_gtd_timer_.Stop();
      if (deferred_tap_down_event_.type != WebInputEvent::Undefined) {
        coalesced_gesture_events_.push_back(deferred_tap_down_event_);
        if (ShouldHandleEventNow())
          render_widget_host_->ForwardGestureEventImmediately(
              deferred_tap_down_event_);
        deferred_tap_down_event_.type = WebInputEvent::Undefined;
        coalesced_gesture_events_.push_back(gesture_event);
        return false;
      }
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureScrollBegin:
    case WebInputEvent::GesturePinchBegin:
      send_gtd_timer_.Stop();
      deferred_tap_down_event_.type = WebInputEvent::Undefined;
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureScrollUpdate:
      MergeOrInsertScrollEvent(gesture_event);
      return ShouldHandleEventNow();
    default:
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
  }

  NOTREACHED();
  return false;
}

void GestureEventFilter::Reset() {
  fling_in_progress_ = false;
  scrolling_in_progress_ = false;
  coalesced_gesture_events_.clear();
  deferred_tap_down_event_.type = WebInputEvent::Undefined;
  debouncing_deferral_queue_.clear();
  send_gtd_timer_.Stop();
  debounce_deferring_timer_.Stop();
  // TODO(rjkroege): Reset the tap suppression controller.
}

void GestureEventFilter::ProcessGestureAck(bool processed, int type) {
  DCHECK_EQ(coalesced_gesture_events_.front().type, type);
  coalesced_gesture_events_.pop_front();
  if (!coalesced_gesture_events_.empty()) {
    WebGestureEvent next_gesture_event = coalesced_gesture_events_.front();
    render_widget_host_->ForwardGestureEventImmediately(next_gesture_event);
  }
}

TapSuppressionController*  GestureEventFilter::GetTapSuppressionController() {
  return tap_suppression_controller_.get();
}

void GestureEventFilter::FlingHasBeenHalted() {
  fling_in_progress_ = false;
}

bool GestureEventFilter::ShouldHandleEventNow() {
  return coalesced_gesture_events_.size() == 1;
}

void GestureEventFilter::SendGestureTapDownNow() {
  // We must not have already sent the deferred TapDown (if we did, we would
  // have stopped the timer, which prevents this task from running - even if
  // it's time had already elapsed).
  DCHECK_EQ(deferred_tap_down_event_.type, WebInputEvent::GestureTapDown);
  coalesced_gesture_events_.push_back(deferred_tap_down_event_);
  if (ShouldHandleEventNow()) {
      render_widget_host_->ForwardGestureEventImmediately(
          deferred_tap_down_event_);
  }
  deferred_tap_down_event_.type = WebInputEvent::Undefined;
}

void GestureEventFilter::SendScrollEndingEventsNow() {
  scrolling_in_progress_ = false;
  for (GestureEventQueue::iterator it =
      debouncing_deferral_queue_.begin();
      it != debouncing_deferral_queue_.end(); it++) {
    if (ShouldForwardForTapDeferral(*it)) {
      render_widget_host_->ForwardGestureEventImmediately(*it);
    }
  }
  debouncing_deferral_queue_.clear();
}

void GestureEventFilter::MergeOrInsertScrollEvent(
    const WebGestureEvent& gesture_event) {
  WebGestureEvent* last_gesture_event = coalesced_gesture_events_.empty() ? 0 :
      &coalesced_gesture_events_.back();
  if (coalesced_gesture_events_.size() > 1 &&
      last_gesture_event->type == gesture_event.type &&
      last_gesture_event->modifiers == gesture_event.modifiers) {
    last_gesture_event->data.scrollUpdate.deltaX +=
        gesture_event.data.scrollUpdate.deltaX;
    last_gesture_event->data.scrollUpdate.deltaY +=
        gesture_event.data.scrollUpdate.deltaY;
    DLOG_IF(WARNING,
            gesture_event.timeStampSeconds <=
            last_gesture_event->timeStampSeconds)
            << "Event time not monotonic?\n";
    DCHECK(last_gesture_event->type == WebInputEvent::GestureScrollUpdate);
    last_gesture_event->timeStampSeconds = gesture_event.timeStampSeconds;
  } else {
    coalesced_gesture_events_.push_back(gesture_event);
  }
}

} // namespace content
<commit_msg>Send pinch events to webkit without putting them into the deboucing deferral queue<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 "content/browser/renderer_host/gesture_event_filter.h"

#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/tap_suppression_controller.h"
#include "content/public/common/content_switches.h"

using WebKit::WebGestureEvent;
using WebKit::WebInputEvent;

namespace content {
namespace {

// Default maximum time between the GestureRecognizer generating a
// GestureTapDown and when it is forwarded to the renderer.
static const int kTapDownDeferralTimeMs = 150;

// Default debouncing interval duration: if a scroll is in progress, non-scroll
// events during this interval are deferred to either its end or discarded on
// receipt of another GestureScrollUpdate.
static const int kDebouncingIntervalTimeMs = 30;

// Sets |*value| to |switchKey| if it exists or sets it to |defaultValue|.
static void GetParamHelper(int* value,
                           int defaultValue,
                           const char switchKey[]) {
  if (*value < 0) {
    *value = defaultValue;
    CommandLine* command_line = CommandLine::ForCurrentProcess();
    std::string command_line_param =
        command_line->GetSwitchValueASCII(switchKey);
    if (!command_line_param.empty()) {
      int v;
      if (base::StringToInt(command_line_param, &v))
        *value = v;
    }
    DCHECK_GE(*value, 0);
  }
}

static int GetTapDownDeferralTimeMs() {
  static int tap_down_deferral_time_window = -1;
  GetParamHelper(&tap_down_deferral_time_window,
                 kTapDownDeferralTimeMs,
                 switches::kTapDownDeferralTimeMs);
  return tap_down_deferral_time_window;
}
} // namespace

GestureEventFilter::GestureEventFilter(RenderWidgetHostImpl* rwhv)
     : render_widget_host_(rwhv),
       fling_in_progress_(false),
       scrolling_in_progress_(false),
       tap_suppression_controller_(new TapSuppressionController(rwhv)),
       maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()),
       debounce_interval_time_ms_(kDebouncingIntervalTimeMs) {
}

GestureEventFilter::~GestureEventFilter() { }

bool GestureEventFilter::ShouldDiscardFlingCancelEvent(
    const WebKit::WebGestureEvent& gesture_event) {
  if (coalesced_gesture_events_.empty() && fling_in_progress_)
    return false;
  GestureEventQueue::reverse_iterator it =
      coalesced_gesture_events_.rbegin();
  while (it != coalesced_gesture_events_.rend()) {
    if (it->type == WebInputEvent::GestureFlingStart)
      return false;
    if (it->type == WebInputEvent::GestureFlingCancel)
      return true;
    it++;
  }
  return true;
}

bool GestureEventFilter::ShouldForwardForBounceReduction(
    const WebGestureEvent& gesture_event) {
  switch (gesture_event.type) {
    case WebInputEvent::GestureScrollUpdate:
      if (!scrolling_in_progress_) {
        debounce_deferring_timer_.Start(FROM_HERE,
              base::TimeDelta::FromMilliseconds(debounce_interval_time_ms_),
              this,
              &GestureEventFilter::SendScrollEndingEventsNow);
      } else {
        // Extend the bounce interval.
        debounce_deferring_timer_.Reset();
      }
      scrolling_in_progress_ = true;
      debouncing_deferral_queue_.clear();
      return true;
    case WebInputEvent::GesturePinchBegin:
    case WebInputEvent::GesturePinchEnd:
    case WebInputEvent::GesturePinchUpdate:
      // TODO(rjkroege): Debounce pinch (http://crbug.com/147647)
      return true;
    default:
      if (scrolling_in_progress_) {
        debouncing_deferral_queue_.push_back(gesture_event);
        return false;
      }
      return true;
  }

  NOTREACHED();
  return false;
}

// NOTE: The filters are applied successively. This simplifies the change.
bool GestureEventFilter::ShouldForward(const WebGestureEvent& gesture_event) {
  if (debounce_interval_time_ms_ ==  0 ||
      ShouldForwardForBounceReduction(gesture_event))
    return ShouldForwardForTapDeferral(gesture_event);
  return false;
}

// TODO(rjkroege): separate touchpad and touchscreen events.
bool GestureEventFilter::ShouldForwardForTapDeferral(
    const WebGestureEvent& gesture_event) {
  switch (gesture_event.type) {
    case WebInputEvent::GestureFlingCancel:
      if (!ShouldDiscardFlingCancelEvent(gesture_event)) {
        coalesced_gesture_events_.push_back(gesture_event);
        fling_in_progress_ = false;
        return ShouldHandleEventNow();
      }
      return false;
    case WebInputEvent::GestureFlingStart:
      fling_in_progress_ = true;
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureTapDown:
      // GestureTapDown is always paired with either a Tap or TapCancel, so
      // it should be impossible to have more than one outstanding at a time.
      DCHECK_EQ(deferred_tap_down_event_.type, WebInputEvent::Undefined);
      deferred_tap_down_event_ = gesture_event;
      send_gtd_timer_.Start(FROM_HERE,
          base::TimeDelta::FromMilliseconds(maximum_tap_gap_time_ms_),
          this,
          &GestureEventFilter::SendGestureTapDownNow);
      return false;
    case WebInputEvent::GestureTapCancel:
      if (deferred_tap_down_event_.type == WebInputEvent::Undefined) {
        // The TapDown has already been put in the queue, must send the
        // corresponding TapCancel as well.
        coalesced_gesture_events_.push_back(gesture_event);
        return ShouldHandleEventNow();
      }
      // Cancelling a deferred TapDown, just drop them on the floor.
      send_gtd_timer_.Stop();
      deferred_tap_down_event_.type = WebInputEvent::Undefined;
      return false;
    case WebInputEvent::GestureTap:
      send_gtd_timer_.Stop();
      if (deferred_tap_down_event_.type != WebInputEvent::Undefined) {
        coalesced_gesture_events_.push_back(deferred_tap_down_event_);
        if (ShouldHandleEventNow())
          render_widget_host_->ForwardGestureEventImmediately(
              deferred_tap_down_event_);
        deferred_tap_down_event_.type = WebInputEvent::Undefined;
        coalesced_gesture_events_.push_back(gesture_event);
        return false;
      }
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureScrollBegin:
    case WebInputEvent::GesturePinchBegin:
      send_gtd_timer_.Stop();
      deferred_tap_down_event_.type = WebInputEvent::Undefined;
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
    case WebInputEvent::GestureScrollUpdate:
      MergeOrInsertScrollEvent(gesture_event);
      return ShouldHandleEventNow();
    default:
      coalesced_gesture_events_.push_back(gesture_event);
      return ShouldHandleEventNow();
  }

  NOTREACHED();
  return false;
}

void GestureEventFilter::Reset() {
  fling_in_progress_ = false;
  scrolling_in_progress_ = false;
  coalesced_gesture_events_.clear();
  deferred_tap_down_event_.type = WebInputEvent::Undefined;
  debouncing_deferral_queue_.clear();
  send_gtd_timer_.Stop();
  debounce_deferring_timer_.Stop();
  // TODO(rjkroege): Reset the tap suppression controller.
}

void GestureEventFilter::ProcessGestureAck(bool processed, int type) {
  DCHECK_EQ(coalesced_gesture_events_.front().type, type);
  coalesced_gesture_events_.pop_front();
  if (!coalesced_gesture_events_.empty()) {
    WebGestureEvent next_gesture_event = coalesced_gesture_events_.front();
    render_widget_host_->ForwardGestureEventImmediately(next_gesture_event);
  }
}

TapSuppressionController*  GestureEventFilter::GetTapSuppressionController() {
  return tap_suppression_controller_.get();
}

void GestureEventFilter::FlingHasBeenHalted() {
  fling_in_progress_ = false;
}

bool GestureEventFilter::ShouldHandleEventNow() {
  return coalesced_gesture_events_.size() == 1;
}

void GestureEventFilter::SendGestureTapDownNow() {
  // We must not have already sent the deferred TapDown (if we did, we would
  // have stopped the timer, which prevents this task from running - even if
  // it's time had already elapsed).
  DCHECK_EQ(deferred_tap_down_event_.type, WebInputEvent::GestureTapDown);
  coalesced_gesture_events_.push_back(deferred_tap_down_event_);
  if (ShouldHandleEventNow()) {
      render_widget_host_->ForwardGestureEventImmediately(
          deferred_tap_down_event_);
  }
  deferred_tap_down_event_.type = WebInputEvent::Undefined;
}

void GestureEventFilter::SendScrollEndingEventsNow() {
  scrolling_in_progress_ = false;
  for (GestureEventQueue::iterator it =
      debouncing_deferral_queue_.begin();
      it != debouncing_deferral_queue_.end(); it++) {
    if (ShouldForwardForTapDeferral(*it)) {
      render_widget_host_->ForwardGestureEventImmediately(*it);
    }
  }
  debouncing_deferral_queue_.clear();
}

void GestureEventFilter::MergeOrInsertScrollEvent(
    const WebGestureEvent& gesture_event) {
  WebGestureEvent* last_gesture_event = coalesced_gesture_events_.empty() ? 0 :
      &coalesced_gesture_events_.back();
  if (coalesced_gesture_events_.size() > 1 &&
      last_gesture_event->type == gesture_event.type &&
      last_gesture_event->modifiers == gesture_event.modifiers) {
    last_gesture_event->data.scrollUpdate.deltaX +=
        gesture_event.data.scrollUpdate.deltaX;
    last_gesture_event->data.scrollUpdate.deltaY +=
        gesture_event.data.scrollUpdate.deltaY;
    DLOG_IF(WARNING,
            gesture_event.timeStampSeconds <=
            last_gesture_event->timeStampSeconds)
            << "Event time not monotonic?\n";
    DCHECK(last_gesture_event->type == WebInputEvent::GestureScrollUpdate);
    last_gesture_event->timeStampSeconds = gesture_event.timeStampSeconds;
  } else {
    coalesced_gesture_events_.push_back(gesture_event);
  }
}

} // namespace content
<|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 "content/browser/tab_contents/tab_contents_view_win.h"

#include "base/bind.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_win.h"
#include "content/browser/tab_contents/interstitial_page_impl.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/web_contents_drag_win.h"
#include "content/browser/tab_contents/web_drag_dest_win.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_view_win_delegate.h"
#include "ui/gfx/screen.h"

using content::RenderViewHost;
using content::RenderWidgetHostView;
using content::WebContents;
using content::WebContentsViewWinDelegate;

namespace {

// We need to have a parent window for the compositing code to work correctly.
//
// A tab will not have a parent HWND whenever it is not active in its
// host window - for example at creation time and when it's in the
// background, so we provide a default widget to host them.
//
// It may be tempting to use GetDesktopWindow() instead, but this is
// problematic as the shell sends messages to children of the desktop
// window that interact poorly with us.
//
// See: http://crbug.com/16476
class TempParent : public ui::WindowImpl {
 public:
  static TempParent* Get() {
    static TempParent* g_temp_parent;
    if (!g_temp_parent) {
      g_temp_parent = new TempParent();

      g_temp_parent->set_window_style(WS_POPUP);
      g_temp_parent->set_window_ex_style(WS_EX_TOOLWINDOW);
      g_temp_parent->Init(GetDesktopWindow(), gfx::Rect());
      EnableWindow(g_temp_parent->hwnd(), FALSE);
    }
    return g_temp_parent;
  }

 private:
  BEGIN_MSG_MAP_EX(TabContentsViewWin)
  END_MSG_MAP()
};

}  // namespace namespace

TabContentsViewWin::TabContentsViewWin(WebContents* web_contents,
                                       WebContentsViewWinDelegate* delegate)
    : tab_contents_(static_cast<TabContents*>(web_contents)),
      view_(NULL),
      delegate_(delegate),
      close_tab_after_drag_ends_(false) {
}

TabContentsViewWin::~TabContentsViewWin() {
  if (IsWindow(hwnd()))
    DestroyWindow(hwnd());
}

void TabContentsViewWin::CreateView(const gfx::Size& initial_size) {
  initial_size_ = initial_size;

  set_window_style(WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

  Init(TempParent::Get()->hwnd(), gfx::Rect(initial_size_));

  // Remove the root view drop target so we can register our own.
  RevokeDragDrop(GetNativeView());
  drag_dest_ = new WebDragDest(hwnd(), tab_contents_);
  if (delegate_.get()) {
    content::WebDragDestDelegate* delegate = delegate_->GetDragDestDelegate();
    if (delegate)
      drag_dest_->set_delegate(delegate);
  }
}

RenderWidgetHostView* TabContentsViewWin::CreateViewForWidget(
    content::RenderWidgetHost* render_widget_host)  {
  if (render_widget_host->GetView()) {
    // During testing, the view will already be set up in most cases to the
    // test view, so we don't want to clobber it with a real one. To verify that
    // this actually is happening (and somebody isn't accidentally creating the
    // view twice), we check for the RVH Factory, which will be set when we're
    // making special ones (which go along with the special views).
    DCHECK(RenderViewHostFactory::has_factory());
    return render_widget_host->GetView();
  }

  view_ = static_cast<RenderWidgetHostViewWin*>(
      RenderWidgetHostView::CreateViewForWidget(render_widget_host));
  view_->CreateWnd(GetNativeView());
  view_->ShowWindow(SW_SHOW);
  view_->SetSize(initial_size_);
  return view_;
}

gfx::NativeView TabContentsViewWin::GetNativeView() const {
  return hwnd();
}

gfx::NativeView TabContentsViewWin::GetContentNativeView() const {
  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  return rwhv ? rwhv->GetNativeView() : NULL;
}

gfx::NativeWindow TabContentsViewWin::GetTopLevelNativeWindow() const {
  return GetParent(GetNativeView());
}

void TabContentsViewWin::GetContainerBounds(gfx::Rect *out) const {
  // Copied from NativeWidgetWin::GetClientAreaScreenBounds().
  RECT r;
  GetClientRect(hwnd(), &r);
  POINT point = { r.left, r.top };
  ClientToScreen(hwnd(), &point);
  *out = gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
}

void TabContentsViewWin::SetPageTitle(const string16& title) {
  // It's possible to get this after the hwnd has been destroyed.
  if (GetNativeView())
    ::SetWindowText(GetNativeView(), title.c_str());
}

void TabContentsViewWin::OnTabCrashed(base::TerminationStatus status,
                                      int error_code) {
  // TODO(avi): No other TCV implementation does anything in this callback. Can
  // this be moved elsewhere so that |OnTabCrashed| can be removed everywhere?
  view_ = NULL;
}

void TabContentsViewWin::SizeContents(const gfx::Size& size) {
  gfx::Rect bounds;
  GetContainerBounds(&bounds);
  if (bounds.size() != size) {
    SetWindowPos(hwnd(), NULL, 0, 0, size.width(), size.height(),
                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  } else {
    // Our size matches what we want but the renderers size may not match.
    // Pretend we were resized so that the renderers size is updated too.
    if (tab_contents_->GetInterstitialPage())
      tab_contents_->GetInterstitialPage()->SetSize(size);
    RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
    if (rwhv)
      rwhv->SetSize(size);
  }
}

void TabContentsViewWin::RenderViewCreated(RenderViewHost* host) {
}

void TabContentsViewWin::Focus() {
  if (tab_contents_->GetInterstitialPage()) {
    tab_contents_->GetInterstitialPage()->Focus();
    return;
  }

  if (delegate_.get() && delegate_->Focus())
    return;

  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  if (rwhv)
    rwhv->Focus();
}

void TabContentsViewWin::SetInitialFocus() {
  if (tab_contents_->FocusLocationBarByDefault())
    tab_contents_->SetFocusToLocationBar(false);
  else
    Focus();
}

void TabContentsViewWin::StoreFocus() {
  if (delegate_.get())
    delegate_->StoreFocus();
}

void TabContentsViewWin::RestoreFocus() {
  if (delegate_.get())
    delegate_->RestoreFocus();
}

bool TabContentsViewWin::IsDoingDrag() const {
  return drag_handler_.get() != NULL;
}

void TabContentsViewWin::CancelDragAndCloseTab() {
  DCHECK(IsDoingDrag());
  // We can't close the tab while we're in the drag and
  // |drag_handler_->CancelDrag()| is async.  Instead, set a flag to cancel
  // the drag and when the drag nested message loop ends, close the tab.
  drag_handler_->CancelDrag();
  close_tab_after_drag_ends_ = true;
}

bool TabContentsViewWin::IsEventTracking() const {
  return false;
}

void TabContentsViewWin::CloseTabAfterEventTracking() {
}

void TabContentsViewWin::GetViewBounds(gfx::Rect* out) const {
  RECT r;
  GetWindowRect(hwnd(), &r);
  *out = gfx::Rect(r);
}

void TabContentsViewWin::CreateNewWindow(
    int route_id,
    const ViewHostMsg_CreateWindow_Params& params) {
  tab_contents_view_helper_.CreateNewWindow(tab_contents_, route_id, params);
}

void TabContentsViewWin::CreateNewWidget(int route_id,
                                         WebKit::WebPopupType popup_type) {
  tab_contents_view_helper_.CreateNewWidget(tab_contents_,
                                            route_id,
                                            false,
                                            popup_type);
}

void TabContentsViewWin::CreateNewFullscreenWidget(int route_id) {
  tab_contents_view_helper_.CreateNewWidget(tab_contents_,
                                            route_id,
                                            true,
                                            WebKit::WebPopupTypeNone);
}

void TabContentsViewWin::ShowCreatedWindow(int route_id,
                                           WindowOpenDisposition disposition,
                                           const gfx::Rect& initial_pos,
                                           bool user_gesture) {
  tab_contents_view_helper_.ShowCreatedWindow(
      tab_contents_, route_id, disposition, initial_pos, user_gesture);
}

void TabContentsViewWin::ShowCreatedWidget(int route_id,
                                           const gfx::Rect& initial_pos) {
  tab_contents_view_helper_.ShowCreatedWidget(tab_contents_,
                                              route_id,
                                              false,
                                              initial_pos);
}

void TabContentsViewWin::ShowCreatedFullscreenWidget(int route_id) {
  tab_contents_view_helper_.ShowCreatedWidget(tab_contents_,
                                              route_id,
                                              true,
                                              gfx::Rect());
}

void TabContentsViewWin::ShowContextMenu(
    const content::ContextMenuParams& params) {
  // Allow WebContentsDelegates to handle the context menu operation first.
  if (tab_contents_->GetDelegate() &&
      tab_contents_->GetDelegate()->HandleContextMenu(params)) {
    return;
  }

  if (delegate_.get())
    delegate_->ShowContextMenu(params);
}

void TabContentsViewWin::ShowPopupMenu(const gfx::Rect& bounds,
                                       int item_height,
                                       double item_font_size,
                                       int selected_item,
                                       const std::vector<WebMenuItem>& items,
                                       bool right_aligned) {
  // External popup menus are only used on Mac.
  NOTIMPLEMENTED();
}

void TabContentsViewWin::StartDragging(const WebDropData& drop_data,
                                       WebKit::WebDragOperationsMask operations,
                                       const SkBitmap& image,
                                       const gfx::Point& image_offset) {
  drag_handler_ = new WebContentsDragWin(
      GetNativeView(),
      tab_contents_,
      drag_dest_,
      base::Bind(&TabContentsViewWin::EndDragging, base::Unretained(this)));
  drag_handler_->StartDragging(drop_data, operations, image, image_offset);
}

void TabContentsViewWin::UpdateDragCursor(WebKit::WebDragOperation operation) {
  drag_dest_->set_drag_cursor(operation);
}

void TabContentsViewWin::GotFocus() {
  if (tab_contents_->GetDelegate())
    tab_contents_->GetDelegate()->WebContentsFocused(tab_contents_);
}

void TabContentsViewWin::TakeFocus(bool reverse) {
  if (tab_contents_->GetDelegate() &&
      !tab_contents_->GetDelegate()->TakeFocus(reverse) &&
      delegate_.get()) {
    delegate_->TakeFocus(reverse);
  }
}

void TabContentsViewWin::EndDragging() {
  drag_handler_ = NULL;
  if (close_tab_after_drag_ends_) {
    close_tab_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(0),
                           this, &TabContentsViewWin::CloseTab);
  }
  tab_contents_->SystemDragEnded();
}

void TabContentsViewWin::CloseTab() {
  RenderViewHost* rvh = tab_contents_->GetRenderViewHost();
  rvh->GetDelegate()->Close(rvh);
}

LRESULT TabContentsViewWin::OnDestroy(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  if (drag_dest_.get()) {
    RevokeDragDrop(GetNativeView());
    drag_dest_ = NULL;
  }
  return 0;
}

LRESULT TabContentsViewWin::OnWindowPosChanged(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(lparam);
  if (window_pos->flags & SWP_NOSIZE)
    return 0;

  gfx::Size size(window_pos->cx, window_pos->cy);
  if (tab_contents_->GetInterstitialPage())
    tab_contents_->GetInterstitialPage()->SetSize(size);
  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  if (rwhv)
    rwhv->SetSize(size);

  if (delegate_.get())
    delegate_->SizeChanged(size);

  return 0;
}

LRESULT TabContentsViewWin::OnMouseDown(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  // Make sure this TabContents is activated when it is clicked on.
  if (tab_contents_->GetDelegate())
    tab_contents_->GetDelegate()->ActivateContents(tab_contents_);
  return 0;
}

LRESULT TabContentsViewWin::OnMouseMove(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  // Let our delegate know that the mouse moved (useful for resetting status
  // bubble state).
  if (tab_contents_->GetDelegate()) {
    tab_contents_->GetDelegate()->ContentsMouseEvent(
        tab_contents_, gfx::Screen::GetCursorScreenPoint(), true);
  }
  return 0;
}

LRESULT TabContentsViewWin::OnReflectedMessage(
    UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  MSG* message = reinterpret_cast<MSG*>(lparam);
  switch (message->message) {
    case WM_MOUSEWHEEL:
      // This message is reflected from the view() to this window.
      if (GET_KEYSTATE_WPARAM(message->wParam) & MK_CONTROL) {
        tab_contents_->GetDelegate()->ContentsZoomChange(
            GET_WHEEL_DELTA_WPARAM(message->wParam) > 0);
        return 1;
      }
    break;
  }
  return 0;
}
<commit_msg>Fix repainting not happening when switching tabs after resizing the browser. I didn't copy this behavior from TCVViews to TCVWin.<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 "content/browser/tab_contents/tab_contents_view_win.h"

#include "base/bind.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_win.h"
#include "content/browser/tab_contents/interstitial_page_impl.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/web_contents_drag_win.h"
#include "content/browser/tab_contents/web_drag_dest_win.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_view_win_delegate.h"
#include "ui/gfx/screen.h"

using content::RenderViewHost;
using content::RenderWidgetHostView;
using content::WebContents;
using content::WebContentsViewWinDelegate;

namespace {

// We need to have a parent window for the compositing code to work correctly.
//
// A tab will not have a parent HWND whenever it is not active in its
// host window - for example at creation time and when it's in the
// background, so we provide a default widget to host them.
//
// It may be tempting to use GetDesktopWindow() instead, but this is
// problematic as the shell sends messages to children of the desktop
// window that interact poorly with us.
//
// See: http://crbug.com/16476
class TempParent : public ui::WindowImpl {
 public:
  static TempParent* Get() {
    static TempParent* g_temp_parent;
    if (!g_temp_parent) {
      g_temp_parent = new TempParent();

      g_temp_parent->set_window_style(WS_POPUP);
      g_temp_parent->set_window_ex_style(WS_EX_TOOLWINDOW);
      g_temp_parent->Init(GetDesktopWindow(), gfx::Rect());
      EnableWindow(g_temp_parent->hwnd(), FALSE);
    }
    return g_temp_parent;
  }

 private:
  BEGIN_MSG_MAP_EX(TabContentsViewWin)
  END_MSG_MAP()
};

}  // namespace namespace

TabContentsViewWin::TabContentsViewWin(WebContents* web_contents,
                                       WebContentsViewWinDelegate* delegate)
    : tab_contents_(static_cast<TabContents*>(web_contents)),
      view_(NULL),
      delegate_(delegate),
      close_tab_after_drag_ends_(false) {
}

TabContentsViewWin::~TabContentsViewWin() {
  if (IsWindow(hwnd()))
    DestroyWindow(hwnd());
}

void TabContentsViewWin::CreateView(const gfx::Size& initial_size) {
  initial_size_ = initial_size;

  set_window_style(WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

  Init(TempParent::Get()->hwnd(), gfx::Rect(initial_size_));

  // Remove the root view drop target so we can register our own.
  RevokeDragDrop(GetNativeView());
  drag_dest_ = new WebDragDest(hwnd(), tab_contents_);
  if (delegate_.get()) {
    content::WebDragDestDelegate* delegate = delegate_->GetDragDestDelegate();
    if (delegate)
      drag_dest_->set_delegate(delegate);
  }
}

RenderWidgetHostView* TabContentsViewWin::CreateViewForWidget(
    content::RenderWidgetHost* render_widget_host)  {
  if (render_widget_host->GetView()) {
    // During testing, the view will already be set up in most cases to the
    // test view, so we don't want to clobber it with a real one. To verify that
    // this actually is happening (and somebody isn't accidentally creating the
    // view twice), we check for the RVH Factory, which will be set when we're
    // making special ones (which go along with the special views).
    DCHECK(RenderViewHostFactory::has_factory());
    return render_widget_host->GetView();
  }

  view_ = static_cast<RenderWidgetHostViewWin*>(
      RenderWidgetHostView::CreateViewForWidget(render_widget_host));
  view_->CreateWnd(GetNativeView());
  view_->ShowWindow(SW_SHOW);
  view_->SetSize(initial_size_);
  return view_;
}

gfx::NativeView TabContentsViewWin::GetNativeView() const {
  return hwnd();
}

gfx::NativeView TabContentsViewWin::GetContentNativeView() const {
  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  return rwhv ? rwhv->GetNativeView() : NULL;
}

gfx::NativeWindow TabContentsViewWin::GetTopLevelNativeWindow() const {
  return GetParent(GetNativeView());
}

void TabContentsViewWin::GetContainerBounds(gfx::Rect *out) const {
  // Copied from NativeWidgetWin::GetClientAreaScreenBounds().
  RECT r;
  GetClientRect(hwnd(), &r);
  POINT point = { r.left, r.top };
  ClientToScreen(hwnd(), &point);
  *out = gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
}

void TabContentsViewWin::SetPageTitle(const string16& title) {
  // It's possible to get this after the hwnd has been destroyed.
  if (GetNativeView())
    ::SetWindowText(GetNativeView(), title.c_str());
}

void TabContentsViewWin::OnTabCrashed(base::TerminationStatus status,
                                      int error_code) {
  // TODO(avi): No other TCV implementation does anything in this callback. Can
  // this be moved elsewhere so that |OnTabCrashed| can be removed everywhere?
  view_ = NULL;
}

void TabContentsViewWin::SizeContents(const gfx::Size& size) {
  gfx::Rect bounds;
  GetContainerBounds(&bounds);
  if (bounds.size() != size) {
    SetWindowPos(hwnd(), NULL, 0, 0, size.width(), size.height(),
                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  } else {
    // Our size matches what we want but the renderers size may not match.
    // Pretend we were resized so that the renderers size is updated too.
    if (tab_contents_->GetInterstitialPage())
      tab_contents_->GetInterstitialPage()->SetSize(size);
    RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
    if (rwhv)
      rwhv->SetSize(size);
  }
}

void TabContentsViewWin::RenderViewCreated(RenderViewHost* host) {
}

void TabContentsViewWin::Focus() {
  if (tab_contents_->GetInterstitialPage()) {
    tab_contents_->GetInterstitialPage()->Focus();
    return;
  }

  if (delegate_.get() && delegate_->Focus())
    return;

  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  if (rwhv)
    rwhv->Focus();
}

void TabContentsViewWin::SetInitialFocus() {
  if (tab_contents_->FocusLocationBarByDefault())
    tab_contents_->SetFocusToLocationBar(false);
  else
    Focus();
}

void TabContentsViewWin::StoreFocus() {
  if (delegate_.get())
    delegate_->StoreFocus();
}

void TabContentsViewWin::RestoreFocus() {
  if (delegate_.get())
    delegate_->RestoreFocus();
}

bool TabContentsViewWin::IsDoingDrag() const {
  return drag_handler_.get() != NULL;
}

void TabContentsViewWin::CancelDragAndCloseTab() {
  DCHECK(IsDoingDrag());
  // We can't close the tab while we're in the drag and
  // |drag_handler_->CancelDrag()| is async.  Instead, set a flag to cancel
  // the drag and when the drag nested message loop ends, close the tab.
  drag_handler_->CancelDrag();
  close_tab_after_drag_ends_ = true;
}

bool TabContentsViewWin::IsEventTracking() const {
  return false;
}

void TabContentsViewWin::CloseTabAfterEventTracking() {
}

void TabContentsViewWin::GetViewBounds(gfx::Rect* out) const {
  RECT r;
  GetWindowRect(hwnd(), &r);
  *out = gfx::Rect(r);
}

void TabContentsViewWin::CreateNewWindow(
    int route_id,
    const ViewHostMsg_CreateWindow_Params& params) {
  tab_contents_view_helper_.CreateNewWindow(tab_contents_, route_id, params);
}

void TabContentsViewWin::CreateNewWidget(int route_id,
                                         WebKit::WebPopupType popup_type) {
  tab_contents_view_helper_.CreateNewWidget(tab_contents_,
                                            route_id,
                                            false,
                                            popup_type);
}

void TabContentsViewWin::CreateNewFullscreenWidget(int route_id) {
  tab_contents_view_helper_.CreateNewWidget(tab_contents_,
                                            route_id,
                                            true,
                                            WebKit::WebPopupTypeNone);
}

void TabContentsViewWin::ShowCreatedWindow(int route_id,
                                           WindowOpenDisposition disposition,
                                           const gfx::Rect& initial_pos,
                                           bool user_gesture) {
  tab_contents_view_helper_.ShowCreatedWindow(
      tab_contents_, route_id, disposition, initial_pos, user_gesture);
}

void TabContentsViewWin::ShowCreatedWidget(int route_id,
                                           const gfx::Rect& initial_pos) {
  tab_contents_view_helper_.ShowCreatedWidget(tab_contents_,
                                              route_id,
                                              false,
                                              initial_pos);
}

void TabContentsViewWin::ShowCreatedFullscreenWidget(int route_id) {
  tab_contents_view_helper_.ShowCreatedWidget(tab_contents_,
                                              route_id,
                                              true,
                                              gfx::Rect());
}

void TabContentsViewWin::ShowContextMenu(
    const content::ContextMenuParams& params) {
  // Allow WebContentsDelegates to handle the context menu operation first.
  if (tab_contents_->GetDelegate() &&
      tab_contents_->GetDelegate()->HandleContextMenu(params)) {
    return;
  }

  if (delegate_.get())
    delegate_->ShowContextMenu(params);
}

void TabContentsViewWin::ShowPopupMenu(const gfx::Rect& bounds,
                                       int item_height,
                                       double item_font_size,
                                       int selected_item,
                                       const std::vector<WebMenuItem>& items,
                                       bool right_aligned) {
  // External popup menus are only used on Mac.
  NOTIMPLEMENTED();
}

void TabContentsViewWin::StartDragging(const WebDropData& drop_data,
                                       WebKit::WebDragOperationsMask operations,
                                       const SkBitmap& image,
                                       const gfx::Point& image_offset) {
  drag_handler_ = new WebContentsDragWin(
      GetNativeView(),
      tab_contents_,
      drag_dest_,
      base::Bind(&TabContentsViewWin::EndDragging, base::Unretained(this)));
  drag_handler_->StartDragging(drop_data, operations, image, image_offset);
}

void TabContentsViewWin::UpdateDragCursor(WebKit::WebDragOperation operation) {
  drag_dest_->set_drag_cursor(operation);
}

void TabContentsViewWin::GotFocus() {
  if (tab_contents_->GetDelegate())
    tab_contents_->GetDelegate()->WebContentsFocused(tab_contents_);
}

void TabContentsViewWin::TakeFocus(bool reverse) {
  if (tab_contents_->GetDelegate() &&
      !tab_contents_->GetDelegate()->TakeFocus(reverse) &&
      delegate_.get()) {
    delegate_->TakeFocus(reverse);
  }
}

void TabContentsViewWin::EndDragging() {
  drag_handler_ = NULL;
  if (close_tab_after_drag_ends_) {
    close_tab_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(0),
                           this, &TabContentsViewWin::CloseTab);
  }
  tab_contents_->SystemDragEnded();
}

void TabContentsViewWin::CloseTab() {
  RenderViewHost* rvh = tab_contents_->GetRenderViewHost();
  rvh->GetDelegate()->Close(rvh);
}

LRESULT TabContentsViewWin::OnDestroy(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  if (drag_dest_.get()) {
    RevokeDragDrop(GetNativeView());
    drag_dest_ = NULL;
  }
  return 0;
}

LRESULT TabContentsViewWin::OnWindowPosChanged(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(lparam);
  if (window_pos->flags & SWP_HIDEWINDOW) {
    tab_contents_->HideContents();
    return 0;
  }

  // The TabContents was shown by a means other than the user selecting a
  // Tab, e.g. the window was minimized then restored.
  if (window_pos->flags & SWP_SHOWWINDOW)
    tab_contents_->ShowContents();

  // Unless we were specifically told not to size, cause the renderer to be
  // sized to the new bounds, which forces a repaint. Not required for the
  // simple minimize-restore case described above, for example, since the
  // size hasn't changed.
  if (window_pos->flags & SWP_NOSIZE)
    return 0;

  gfx::Size size(window_pos->cx, window_pos->cy);
  if (tab_contents_->GetInterstitialPage())
    tab_contents_->GetInterstitialPage()->SetSize(size);
  RenderWidgetHostView* rwhv = tab_contents_->GetRenderWidgetHostView();
  if (rwhv)
    rwhv->SetSize(size);

  if (delegate_.get())
    delegate_->SizeChanged(size);

  return 0;
}

LRESULT TabContentsViewWin::OnMouseDown(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  // Make sure this TabContents is activated when it is clicked on.
  if (tab_contents_->GetDelegate())
    tab_contents_->GetDelegate()->ActivateContents(tab_contents_);
  return 0;
}

LRESULT TabContentsViewWin::OnMouseMove(
    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  // Let our delegate know that the mouse moved (useful for resetting status
  // bubble state).
  if (tab_contents_->GetDelegate()) {
    tab_contents_->GetDelegate()->ContentsMouseEvent(
        tab_contents_, gfx::Screen::GetCursorScreenPoint(), true);
  }
  return 0;
}

LRESULT TabContentsViewWin::OnReflectedMessage(
    UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled) {
  MSG* message = reinterpret_cast<MSG*>(lparam);
  switch (message->message) {
    case WM_MOUSEWHEEL:
      // This message is reflected from the view() to this window.
      if (GET_KEYSTATE_WPARAM(message->wParam) & MK_CONTROL) {
        tab_contents_->GetDelegate()->ContentsZoomChange(
            GET_WHEEL_DELTA_WPARAM(message->wParam) > 0);
        return 1;
      }
    break;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <inttypes.h>

#include "mutex.hpp"
#include "task.hpp"
#include "EiTOSConfig.hpp"
#include "port/port.hpp"

uint8_t MutexUsed = 0;
uint8_t MutexTaken[MAX_MUTEX] = {false};

mutex::mutex() {
    MutexUsed++;
    this->nr = MutexUsed;
}

void mutex::give() {
    if ( MutexTaken[this->nr] == false )
        return;
    MutexTaken[this->nr] = false;
    for (uint8_t i = 0; i < TaskQueue.size(); i++) {
        if ( TaskQueue[i].blockingMutexNr == this->nr ) {
            TaskStruct_t taskRemoved = TaskQueue[i];
            taskRemoved.blockingMutexNr = 0;
            TaskQueue.remove(i);
            TaskQueue.push(taskRemoved);
        }
    }
    TriggerSysTick();
}

void mutex::take() {
    MutexTaken[this->nr] = true;
    TaskStruct_t task = TaskQueue.front();
    TaskQueue.pop();
    task.blockingMutexNr = this->nr;
    TaskQueue.push(task);
    TriggerSysTick();
}

bool mutex::take(uint32_t timeout) {
}
<commit_msg>extracting task operating functions in mutex struct<commit_after>#include <inttypes.h>

#include "mutex.hpp"
#include "task.hpp"
#include "EiTOSConfig.hpp"
#include "port/port.hpp"

uint8_t MutexUsed = 0;
uint8_t MutexTaken[MAX_MUTEX] = {false};

mutex::mutex() {
    MutexUsed++;
    this->nr = MutexUsed;
}

static inline void unlockTasksByMutex(uint8_t mutexNr) {
    for (uint8_t i = 0; i < TaskQueue.size(); i++) {
        if ( TaskQueue[i].blockingMutexNr == mutexNr ) {
            TaskStruct_t taskRemoved = TaskQueue[i];
            taskRemoved.blockingMutexNr = 0;
            TaskQueue.remove(i);
            TaskQueue.push(taskRemoved);
        }
    }
}

void mutex::give() {
    if ( MutexTaken[this->nr] == false )
        return;
    MutexTaken[this->nr] = false;
    unlockTasksByMutex(this->nr);
    TriggerSysTick();
}

static inline void lockTaskByMutex(uint8_t mutexNr) {
    TaskStruct_t task = TaskQueue.front();
    TaskQueue.pop();
    task.blockingMutexNr = mutexNr;
    TaskQueue.push(task);
}

void mutex::take() {
    MutexTaken[this->nr] = true;
    lockTaskByMutex(this->nr);
    TriggerSysTick();
}

bool mutex::take(uint32_t timeout) {
}
<|endoftext|>


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

#include "Utilities/UIDGenerator.hpp"

//------------------------------------------------------------------------------------------

namespace Ocular
{
    namespace Utils
    {
        //----------------------------------------------------------------------------------
        // CONSTRUCTORS
        //----------------------------------------------------------------------------------

        UIDGenerator::UIDGenerator()
        {
            m_UID = 0;
        }

        UIDGenerator::~UIDGenerator()
        {

        }

        //----------------------------------------------------------------------------------
        // PUBLIC METHODS
        //----------------------------------------------------------------------------------

        unsigned UIDGenerator::next()
        {
            m_Mutex.lock();
            m_UID++;
            m_Mutex.unlock();

            return m_UID;
        }

        //----------------------------------------------------------------------------------
        // PROTECTED METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // PRIVATE METHODS
        //----------------------------------------------------------------------------------

    }
}<commit_msg>UIDGenerator should actually be thread-safe now<commit_after>/**
* Copyright 2014 Steven T Sell (ssell@ocularinteractive.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "Utilities/UIDGenerator.hpp"

//------------------------------------------------------------------------------------------

namespace Ocular
{
    namespace Utils
    {
        //----------------------------------------------------------------------------------
        // CONSTRUCTORS
        //----------------------------------------------------------------------------------

        UIDGenerator::UIDGenerator()
        {
            m_UID = 0;
        }

        UIDGenerator::~UIDGenerator()
        {

        }

        //----------------------------------------------------------------------------------
        // PUBLIC METHODS
        //----------------------------------------------------------------------------------

        unsigned UIDGenerator::next()
        {
            int returnID;

            m_Mutex.lock();
            returnID = ++m_UID;
            m_Mutex.unlock();

            return returnID;
        }

        //----------------------------------------------------------------------------------
        // PROTECTED METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // PRIVATE METHODS
        //----------------------------------------------------------------------------------

    }
}<|endoftext|>


<commit_before>#include "Fb2File.h"
#include "../DesktopEditor/xml/include/xmlutils.h"
#include "../DesktopEditor/common/Base64.h"
#include "../DesktopEditor/common/File.h"

#include <vector>
#include <map>

// Тэг author
struct author
{
    std::wstring first_name;
    std::wstring middle_name;
    std::wstring last_name;
    std::wstring nickname;
    std::vector<std::wstring> home_page;
    std::vector<std::wstring> email;
};

class CFb2File_Private
{
public:
    XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader
    std::wstring m_sFile;                    // Имя файла
    std::wstring m_sDstFolder;               // Путь к результату
    // Контент файла
    std::vector<std::wstring> m_arGenres; // Жанры
    std::vector<author> m_arAuthors;      // Авторы
    std::vector<author> m_arTranslator;   // Переводчики

    std::wstring m_sBookTitle; // Название
    std::wstring m_sLang;      // Язык после перевода

    std::wstring* m_pAnnotation;                    // Аннотация
    std::wstring* m_pKeywords;                      // Ключевые слова
    std::pair<std::wstring, std::wstring>* m_pDate; // Дата
    std::wstring* m_pCoverpage;                     // Обложка
    std::wstring* m_pSrcLang;                       // Язык до перевода

    std::map<std::wstring, std::wstring> m_mXmlns;    // Ссылки
    std::map<std::wstring, std::wstring> m_mSequence; // Серии книг
    std::map<std::wstring, std::wstring> m_mImage;    // Картинки

public:
    CFb2File_Private()
    {
        m_pAnnotation = NULL;
        m_pKeywords = NULL;
        m_pDate = NULL;
        m_pCoverpage = NULL;
        m_pSrcLang = NULL;
    }

    ~CFb2File_Private()
    {
        m_oLightReader.Clear();
        m_arGenres.clear();
        m_arAuthors.clear();
        m_arTranslator.clear();
        m_mXmlns.clear();
        m_mSequence.clear();
        m_mImage.clear();
        RELEASEARRAYOBJECTS(m_pAnnotation);
        RELEASEARRAYOBJECTS(m_pKeywords);
        RELEASEARRAYOBJECTS(m_pDate);
        RELEASEARRAYOBJECTS(m_pCoverpage);
        RELEASEARRAYOBJECTS(m_pSrcLang);
    }

    // Читает и проверят соответствует ли текущий раздел ожиданиям
    bool isSection(const std::wstring& sName)
    {
        if(!m_oLightReader.ReadNextNode())
            return false;
        if(m_oLightReader.GetName() != sName)
            return false;
        return true;
    }

    // Читает поля автора
    bool readAuthor(std::vector<author>& arAuthor)
    {
        author oAuthor;
        int nDepth = m_oLightReader.GetDepth();
        while(m_oLightReader.ReadNextSiblingNode(nDepth))
        {
            std::wstring sName = m_oLightReader.GetName();
            std::wstring sRes;
            if(sName == L"first-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.first_name = sRes;
            }
            else if(sName == L"middle-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.middle_name = sRes;
            }
            else if(sName == L"last-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.last_name = sRes;
            }
            else if(sName == L"nickname")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.nickname = sRes;
            }
            else if(sName == L"home-page")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.home_page.push_back(sRes);
            }
            else if(sName == L"email")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.email.push_back(sRes);
            }
            else
                return false;
        }
        arAuthor.push_back(oAuthor);
        return true;
    }

    // Возвращает содержание узла
    std::wstring content()
    {
        std::wstring sRes = L"";
        if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth()))
            sRes = m_oLightReader.GetText();
        return sRes;
    }

    std::string contentA(std::wstring is)
    {
        std::string sRes = "";
        if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth()))
            sRes = m_oLightReader.GetTextA();
        return sRes;
    }
};

CFb2File::CFb2File()
{
    m_internal = new CFb2File_Private();
}

CFb2File::~CFb2File()
{
    RELEASEOBJECT(m_internal);
}

// Проверяет, соответствует ли fb2 файл формату
bool CFb2File::IsFb2File(const std::wstring& sFile)
{
    if (!m_internal->m_oLightReader.FromFile(sFile))
        return false;

    // Читаем FictionBook
    if(!m_internal->isSection(L"FictionBook"))
        return false;
    while(m_internal->m_oLightReader.MoveToNextAttribute())
        m_internal->m_mXmlns.insert(std::make_pair(m_internal->m_oLightReader.GetName(), m_internal->m_oLightReader.GetText()));
    m_internal->m_sFile = sFile;
    return true;
}

// Выставление временной (рабочей) папки
void CFb2File::SetImpDirectory(const std::wstring& sFolder)
{
    m_internal->m_sDstFolder = sFolder;
}

// Проверяет, соответствует ли fb2 файл формату
// sPath - путь к сохраненному файлу, sDirectory - путь к сохраненным картинкам
int CFb2File::Convert (const std::wstring& sPath, const std::wstring& sDirectory)
{
    // Читаем description
    if(!m_internal->isSection(L"description"))
        return false;

    // Читаем наполнение description
    // Читаем title-info
    if(!m_internal->isSection(L"title-info"))
        return false;

    // Читаем наполнение title-info
    // Читаем genre (один или более)
    if(!m_internal->isSection(L"genre"))
        return false;
    do
    {
        std::wstring sGenre;
        sGenre = m_internal->content();
        if(sGenre == L"")
            return false;
        m_internal->m_arGenres.push_back(sGenre);
    } while(m_internal->isSection(L"genre"));

    // Читаем author (один или более)
    do
    {
        if(!m_internal->readAuthor(m_internal->m_arAuthors))
            return false;
    } while(m_internal->isSection(L"author"));

    // Читаем book-title
    if(m_internal->m_oLightReader.GetName() != L"book-title")
        return false;
    std::wstring sBookTitle;
    sBookTitle = m_internal->content();
    if(sBookTitle == L"")
        return false;
    m_internal->m_sBookTitle = sBookTitle;

    // Читаем все до lang
    while(!m_internal->isSection(L"lang"))
    {
        if(m_internal->m_oLightReader.GetDepth() == 0)
            return false;
        std::wstring sRes;
        std::wstring sName = m_internal->m_oLightReader.GetName();

        // Читаем annotation (ноль или один)
        if(sName == L"annotation")
        {
            // Содержит форматированный текст - НЕ РЕАЛИЗОВАНО
            if(m_internal->m_pAnnotation)
                return false;
            m_internal->m_pAnnotation = new std::wstring[1];
            *m_internal->m_pAnnotation = L"";
            int nDepth = m_internal->m_oLightReader.GetDepth();
            while(m_internal->m_oLightReader.ReadNextSiblingNode(nDepth))
            {
                *m_internal->m_pAnnotation += m_internal->content();
            }
        }
        // Читаем keywords (ноль или один)
        else if(sName == L"keywords")
        {
            if(m_internal->m_pKeywords)
                return false;
            m_internal->m_pKeywords = new std::wstring[1];
            sRes = m_internal->content();
            if(sRes == L"")
                return false;
            *m_internal->m_pKeywords = sRes;
        }
        // Читаем date (ноль или один)
        else if(sName == L"date")
        {
            if(m_internal->m_pDate)
                return false;
            m_internal->m_pDate = new std::pair<std::wstring, std::wstring>[1];
            std::wstring sDate = L"";
            if(m_internal->m_oLightReader.MoveToNextAttribute())
            {
                sDate = m_internal->m_oLightReader.GetText();
                m_internal->m_oLightReader.MoveToElement();
            }
            sRes = m_internal->content();
            if(sRes == L"")
                return false;
            *m_internal->m_pDate = make_pair(sDate, sRes);
        }
        // Читаем coverpage (ноль или один)
        else if(sName == L"coverpage")
        {
            if(m_internal->m_pCoverpage)
                return false;
            m_internal->m_pCoverpage = new std::wstring[1];
            if(!m_internal->m_oLightReader.ReadNextSiblingNode(m_internal->m_oLightReader.GetDepth()))
                return false;
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            sRes = m_internal->m_oLightReader.GetText();
            if(sRes == L"")
                return false;
            m_internal->m_oLightReader.MoveToElement();
            *m_internal->m_pCoverpage = sRes;
        }
    }

    // Читаем lang
    if(m_internal->m_oLightReader.GetName() != L"lang")
        return false;
    std::wstring sLang;
    sLang = m_internal->content();
    if(sLang == L"")
        return false;
    m_internal->m_sLang = sLang;

    // Читаем все до document-info
    while(!m_internal->isSection(L"document-info"))
    {
        if(m_internal->m_oLightReader.GetDepth() == 0)
            return false;
        std::wstring sRes;
        std::wstring sName = m_internal->m_oLightReader.GetName();

        // Читаем src-lang (ноль или один)
        if(sName == L"src-lang")
        {
            if(m_internal->m_pSrcLang)
                return false;
            m_internal->m_pSrcLang = new std::wstring[1];
            sRes = m_internal->content();
            if(sRes == L"")
                return false;
            *m_internal->m_pSrcLang = sRes;
        }
        // Читаем translator (любое)
        else if(sName == L"translator")
        {
            if(!m_internal->readAuthor(m_internal->m_arTranslator))
                return false;
        }
        // Читаем sequence (любое)
        else if(sName == L"sequence")
        {
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            std::wstring sSName = m_internal->m_oLightReader.GetText();
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            std::wstring sSNumber = m_internal->m_oLightReader.GetText();
            m_internal->m_mSequence.insert(std::make_pair(sSName, sSNumber));
        }
    }

    // ПРОЧИТАН разде title-info

    // ПРОПУСКАЕМ body

    while(m_internal->m_oLightReader.ReadNextNode())
    {
        // Читает картинки
        if(m_internal->m_oLightReader.GetName() == L"binary")
        {
            std::wstring sId;
            std::wstring sContentType;

            // Читает id
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            sId = m_internal->m_oLightReader.GetText();

            // Читает content-type
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            sContentType = m_internal->m_oLightReader.GetText();

            m_internal->m_mImage.insert(std::make_pair(sId, sContentType));
            m_internal->m_oLightReader.MoveToElement();

            // Пишет картинку в файл
            NSFile::CFileBinary oImageWriter;
            if (!oImageWriter.CreateFileW(sDirectory + sId))
                return false;
            std::string sBase64 = m_internal->contentA(sId);
            int nSrcLen = (int)sBase64.length();
            int nDecodeLen = NSBase64::Base64DecodeGetRequiredLength(nSrcLen);
            BYTE* pImageData = new BYTE[nDecodeLen];
            if (TRUE == NSBase64::Base64Decode(sBase64.c_str(), nSrcLen, pImageData, &nDecodeLen))
                oImageWriter.WriteFile(pImageData, (DWORD)nDecodeLen);
            RELEASEARRAYOBJECTS(pImageData);
            oImageWriter.CloseFile();
        }
    }
    return TRUE;
}
<commit_msg>read src-title-info<commit_after>#include "Fb2File.h"
#include "../DesktopEditor/xml/include/xmlutils.h"
#include "../DesktopEditor/common/Base64.h"
#include "../DesktopEditor/common/File.h"

#include <vector>
#include <map>

// Информация об авторе книги. Тэг author, translator
struct SAuthor
{
    std::wstring first_name;
    std::wstring middle_name;
    std::wstring last_name;
    std::wstring nickname;
    std::vector<std::wstring> home_page;
    std::vector<std::wstring> email;
};

// Описание информации о произведении. Тэг title-info, src-title-info
struct STitleInfo
{
    std::vector<std::wstring> m_arGenres; // Жанры
    std::vector<SAuthor> m_arAuthors;     // Авторы
    std::vector<SAuthor> m_arTranslator;  // Переводчики

    std::wstring m_sBookTitle; // Название
    std::wstring m_sLang;      // Язык после перевода

    std::wstring* m_pAnnotation;                    // Аннотация
    std::wstring* m_pKeywords;                      // Ключевые слова
    std::pair<std::wstring, std::wstring>* m_pDate; // Дата
    std::wstring* m_pCoverpage;                     // Обложка
    std::wstring* m_pSrcLang;                       // Язык до перевода

    std::map<std::wstring, std::wstring> m_mSequence; // Серии книг

    STitleInfo()
    {
        m_pAnnotation = NULL;
        m_pKeywords = NULL;
        m_pDate = NULL;
        m_pCoverpage = NULL;
        m_pSrcLang = NULL;
    }

    ~STitleInfo()
    {
        m_arGenres.clear();
        m_arAuthors.clear();
        m_arTranslator.clear();

        m_mSequence.clear();

        RELEASEARRAYOBJECTS(m_pAnnotation);
        RELEASEARRAYOBJECTS(m_pKeywords);
        RELEASEARRAYOBJECTS(m_pDate);
        RELEASEARRAYOBJECTS(m_pCoverpage);
        RELEASEARRAYOBJECTS(m_pSrcLang);
    }
};

class CFb2File_Private
{
public:
    XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader
    std::wstring m_sFile;                    // Имя файла
    std::wstring m_sDstFolder;               // Путь к результату

    STitleInfo m_oTitleInfo; // Данные о книге

    STitleInfo* m_pSrcTitleInfo; // Данные об исходнике книги
    /*
    std::vector<std::wstring> m_arGenres; // Жанры
    std::vector<SAuthor> m_arAuthors;      // Авторы
    std::vector<SAuthor> m_arTranslator;   // Переводчики

    std::wstring m_sBookTitle; // Название
    std::wstring m_sLang;      // Язык после перевода

    std::wstring* m_pAnnotation;                    // Аннотация
    std::wstring* m_pKeywords;                      // Ключевые слова
    std::pair<std::wstring, std::wstring>* m_pDate; // Дата
    std::wstring* m_pCoverpage;                     // Обложка
    std::wstring* m_pSrcLang;                       // Язык до перевода

    std::map<std::wstring, std::wstring> m_mSequence; // Серии книг
    */
    std::map<std::wstring, std::wstring> m_mXmlns;    // Ссылки
    std::map<std::wstring, std::wstring> m_mImage;    // Картинки

public:
    CFb2File_Private()
    {
        m_pSrcTitleInfo = NULL;
    }

    ~CFb2File_Private()
    {
        m_oLightReader.Clear();
        m_mXmlns.clear();
        m_mImage.clear();
        if(m_pSrcTitleInfo)
            delete m_pSrcTitleInfo;
    }

    // Читает и проверят соответствует ли текущий раздел ожиданиям
    bool isSection(const std::wstring& sName)
    {
        if(!m_oLightReader.ReadNextNode())
            return false;
        if(m_oLightReader.GetName() != sName)
            return false;
        return true;
    }

    // Читает поля автора
    bool readAuthor(std::vector<SAuthor>& arAuthor)
    {
        SAuthor oAuthor;
        int nDepth = m_oLightReader.GetDepth();
        while(m_oLightReader.ReadNextSiblingNode(nDepth))
        {
            std::wstring sName = m_oLightReader.GetName();
            std::wstring sRes;
            if(sName == L"first-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.first_name = sRes;
            }
            else if(sName == L"middle-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.middle_name = sRes;
            }
            else if(sName == L"last-name")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.last_name = sRes;
            }
            else if(sName == L"nickname")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.nickname = sRes;
            }
            else if(sName == L"home-page")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.home_page.push_back(sRes);
            }
            else if(sName == L"email")
            {
                sRes = content();
                if(sRes == L"")
                    return false;
                oAuthor.email.push_back(sRes);
            }
            else
                return false;
        }
        arAuthor.push_back(oAuthor);
        return true;
    }

    bool getTitleInfo(STitleInfo& oTitleInfo)
    {
        // Читаем genre (один или более)
        if(!isSection(L"genre"))
            return false;
        do
        {
            std::wstring sGenre;
            sGenre = content();
            if(sGenre == L"")
                return false;
            oTitleInfo.m_arGenres.push_back(sGenre);
        } while(isSection(L"genre"));

        // Читаем author (один или более)
        do
        {
            if(!readAuthor(oTitleInfo.m_arAuthors))
                return false;
        } while(isSection(L"author"));

        // Читаем book-title
        if(m_oLightReader.GetName() != L"book-title")
            return false;
        std::wstring sBookTitle;
        sBookTitle = content();
        if(sBookTitle == L"")
            return false;
        oTitleInfo.m_sBookTitle = sBookTitle;

        // Читаем все до lang
        while(!isSection(L"lang"))
        {
            if(m_oLightReader.GetDepth() == 0)
                return false;
            std::wstring sRes;
            std::wstring sName = m_oLightReader.GetName();

            // Читаем annotation (ноль или один)
            if(sName == L"annotation")
            {
                // Содержит форматированный текст - НЕ РЕАЛИЗОВАНО
                if(oTitleInfo.m_pAnnotation)
                    return false;
                oTitleInfo.m_pAnnotation = new std::wstring[1];
                *oTitleInfo.m_pAnnotation = L"";
                int nDepth = m_oLightReader.GetDepth();
                while(m_oLightReader.ReadNextSiblingNode(nDepth))
                {
                    *oTitleInfo.m_pAnnotation += content();
                }
            }
            // Читаем keywords (ноль или один)
            else if(sName == L"keywords")
            {
                if(oTitleInfo.m_pKeywords)
                    return false;
                oTitleInfo.m_pKeywords = new std::wstring[1];
                sRes = content();
                if(sRes == L"")
                    return false;
                *oTitleInfo.m_pKeywords = sRes;
            }
            // Читаем date (ноль или один)
            else if(sName == L"date")
            {
                if(oTitleInfo.m_pDate)
                    return false;
                oTitleInfo.m_pDate = new std::pair<std::wstring, std::wstring>[1];
                std::wstring sDate = L"";
                if(m_oLightReader.MoveToNextAttribute())
                {
                    sDate = m_oLightReader.GetText();
                    m_oLightReader.MoveToElement();
                }
                sRes = content();
                if(sRes == L"")
                    return false;
                *oTitleInfo.m_pDate = make_pair(sDate, sRes);
            }
            // Читаем coverpage (ноль или один)
            else if(sName == L"coverpage")
            {
                if(oTitleInfo.m_pCoverpage)
                    return false;
                oTitleInfo.m_pCoverpage = new std::wstring[1];
                if(!m_oLightReader.ReadNextSiblingNode(m_oLightReader.GetDepth()))
                    return false;
                if(!m_oLightReader.MoveToNextAttribute())
                    return false;
                sRes = m_oLightReader.GetText();
                if(sRes == L"")
                    return false;
                m_oLightReader.MoveToElement();
                *oTitleInfo.m_pCoverpage = sRes;
            }
        }

        // Читаем lang
        if(m_oLightReader.GetName() != L"lang")
            return false;
        std::wstring sLang;
        sLang = content();
        if(sLang == L"")
            return false;
        oTitleInfo.m_sLang = sLang;

        // Читаем все до document-info
        while(!isSection(L"document-info"))
        {
            if(m_oLightReader.GetDepth() == 0)
                return false;
            std::wstring sRes;
            std::wstring sName = m_oLightReader.GetName();

            // Читаем src-lang (ноль или один)
            if(sName == L"src-lang")
            {
                if(oTitleInfo.m_pSrcLang)
                    return false;
                oTitleInfo.m_pSrcLang = new std::wstring[1];
                sRes = content();
                if(sRes == L"")
                    return false;
                *oTitleInfo.m_pSrcLang = sRes;
            }
            // Читаем translator (любое)
            else if(sName == L"translator")
            {
                if(!readAuthor(oTitleInfo.m_arTranslator))
                    return false;
            }
            // Читаем sequence (любое)
            else if(sName == L"sequence")
            {
                if(!m_oLightReader.MoveToNextAttribute())
                    return false;
                std::wstring sSName = m_oLightReader.GetText();
                if(!m_oLightReader.MoveToNextAttribute())
                    return false;
                std::wstring sSNumber = m_oLightReader.GetText();
                oTitleInfo.m_mSequence.insert(std::make_pair(sSName, sSNumber));
            }
            else if(sName == L"src-title-info")
            {
                break;
            }
        }
        return true;
    }

    // Возвращает содержание узла
    std::wstring content()
    {
        std::wstring sRes = L"";
        if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth()))
            sRes = m_oLightReader.GetText();
        return sRes;
    }

    std::string contentA(std::wstring is)
    {
        std::string sRes = "";
        if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth()))
            sRes = m_oLightReader.GetTextA();
        return sRes;
    }
};

CFb2File::CFb2File()
{
    m_internal = new CFb2File_Private();
}

CFb2File::~CFb2File()
{
    RELEASEOBJECT(m_internal);
}

// Проверяет, соответствует ли fb2 файл формату
bool CFb2File::IsFb2File(const std::wstring& sFile)
{
    if (!m_internal->m_oLightReader.FromFile(sFile))
        return false;

    // Читаем FictionBook
    if(!m_internal->isSection(L"FictionBook"))
        return false;
    while(m_internal->m_oLightReader.MoveToNextAttribute())
        m_internal->m_mXmlns.insert(std::make_pair(m_internal->m_oLightReader.GetName(), m_internal->m_oLightReader.GetText()));
    m_internal->m_sFile = sFile;
    return true;
}

// Выставление временной (рабочей) папки
void CFb2File::SetImpDirectory(const std::wstring& sFolder)
{
    m_internal->m_sDstFolder = sFolder;
}

// Проверяет, соответствует ли fb2 файл формату
// sPath - путь к сохраненному файлу, sDirectory - путь к сохраненным картинкам
int CFb2File::Convert (const std::wstring& sPath, const std::wstring& sDirectory)
{
    // Читаем description
    if(!m_internal->isSection(L"description"))
        return false;

    // Читаем наполнение description
    // Читаем title-info
    if(!m_internal->isSection(L"title-info"))
        return false;

    // Читаем наполнение title-info
    if(!m_internal->getTitleInfo(m_internal->m_oTitleInfo))
        return false;

    if(m_internal->m_oLightReader.GetName() == L"src-title-info")
    {
        m_internal->m_pSrcTitleInfo = new STitleInfo();
        if(!m_internal->getTitleInfo(*m_internal->m_pSrcTitleInfo))
            return false;
    }

    // ПРОПУСКАЕМ body

    while(m_internal->m_oLightReader.ReadNextNode())
    {
        // Читает картинки
        if(m_internal->m_oLightReader.GetName() == L"binary")
        {
            std::wstring sId;
            std::wstring sContentType;

            // Читает id
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            sId = m_internal->m_oLightReader.GetText();

            // Читает content-type
            if(!m_internal->m_oLightReader.MoveToNextAttribute())
                return false;
            sContentType = m_internal->m_oLightReader.GetText();

            m_internal->m_mImage.insert(std::make_pair(sId, sContentType));
            m_internal->m_oLightReader.MoveToElement();

            // Пишет картинку в файл
            NSFile::CFileBinary oImageWriter;
            if (!oImageWriter.CreateFileW(sDirectory + sId))
                return false;
            std::string sBase64 = m_internal->contentA(sId);
            int nSrcLen = (int)sBase64.length();
            int nDecodeLen = NSBase64::Base64DecodeGetRequiredLength(nSrcLen);
            BYTE* pImageData = new BYTE[nDecodeLen];
            if (TRUE == NSBase64::Base64Decode(sBase64.c_str(), nSrcLen, pImageData, &nDecodeLen))
                oImageWriter.WriteFile(pImageData, (DWORD)nDecodeLen);
            RELEASEARRAYOBJECTS(pImageData);
            oImageWriter.CloseFile();
        }
    }
    return TRUE;
}
<|endoftext|>


<commit_before>AliAnalysisTaskTrigChEff *AddTaskMTRchamberEfficiency(Bool_t useGhosts = kFALSE)
{
  //
  // Task for the determination of the MUON trigger chamber efficiency
  //
  // stocco@subatech.in2p3.fr
  //

  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTask", "No analysis manager to connect to.");
    return NULL;
  }

  // Create the task
  AliAnalysisTaskTrigChEff* taskTrigChEff = new AliAnalysisTaskTrigChEff("TriggerChamberEfficiency");
  taskTrigChEff->SetUseGhostTracks(useGhosts);
  // Add to the manager
  mgr->AddTask(taskTrigChEff);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cOutputTrigChEff = mgr->CreateContainer("triggerChamberEff", TList::Class(), AliAnalysisManager::kOutputContainer, "MUON.TriggerEfficiencyMap.root");

  // Attach input
  mgr->ConnectInput(taskTrigChEff,0,mgr->GetCommonInputContainer());
  // Attach output
  mgr->ConnectOutput(taskTrigChEff,0,cOutputTrigChEff);

  return taskTrigChEff;
}
<commit_msg>changes by Diego<commit_after>AliAnalysisTaskTrigChEff *AddTaskMTRchamberEfficiency(Bool_t useGhosts = kFALSE)
{
  //
  // Task for the determination of the MUON trigger chamber efficiency
  //
  // stocco@subatech.in2p3.fr
  //

  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskMTRchamberEfficiency", "No analysis manager to connect to.");
    return NULL;
  }

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler()) {
    ::Error("AliAnalysisTaskTrigChEff", "This task requires an input event handler");
    return NULL;
  }

  // Create the task
  AliAnalysisTaskTrigChEff* taskTrigChEff = new AliAnalysisTaskTrigChEff("TriggerChamberEfficiency");
  taskTrigChEff->SetUseGhostTracks(useGhosts);
  // Add to the manager
  mgr->AddTask(taskTrigChEff);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cOutputTrigChEff = mgr->CreateContainer("triggerChamberEff", TList::Class(), AliAnalysisManager::kOutputContainer, "MUON.TriggerEfficiencyMap.root");

  // Attach input
  mgr->ConnectInput(taskTrigChEff,0,mgr->GetCommonInputContainer());
  // Attach output
  mgr->ConnectOutput(taskTrigChEff,1,cOutputTrigChEff);

  return taskTrigChEff;
}
<|endoftext|>


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

/// \file
/// Tests for the Mesh class.

#include "gtest/gtest.h"

#include "SurgSim/DataStructures/MeshVertex.h"
#include "SurgSim/DataStructures/UnitTests/MockObjects.h"
#include "SurgSim/Math/Vector.h"

using SurgSim::Math::Vector3d;

/// Vertex
typedef SurgSim::DataStructures::MeshVertex<MockVertexData> MockVertex;

TEST(MeshVertexTest, InitTest)
{
	Vector3d position(0.0, 0.0, 0.0);
	MockVertexData data(0, Vector3d(1.0, 0.0, 0.0));
	ASSERT_NO_THROW({MockVertex vertex(position, data);});
}

TEST(MeshVertexTest, VertexTest)
{
	Vector3d position(1.0, 2.0, 3.0);
	MockVertexData data(2, Vector3d(1.0, 0.0, 0.0));
	MockVertex vertex(position, data);

	EXPECT_EQ(position, vertex.position);
	EXPECT_EQ(data, vertex.data);

	{
		const MockVertexData& data = vertex.data;
		EXPECT_EQ(2, data.getId());
		EXPECT_EQ(Vector3d(1.0, 0.0, 0.0), data.getNormal());
	}
}<commit_msg>Tests for MeshVertex with no data (void template parameter).<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2012-2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// \file
/// Tests for the Mesh class.

#include "gtest/gtest.h"

#include "SurgSim/DataStructures/MeshVertex.h"
#include "SurgSim/DataStructures/UnitTests/MockObjects.h"
#include "SurgSim/Math/Vector.h"

using SurgSim::DataStructures::MeshVertex;
using SurgSim::Math::Vector3d;

/// Vertex with ID and normal data
typedef SurgSim::DataStructures::MeshVertex<MockVertexData> MockVertex;
/// Vertex with no data
typedef SurgSim::DataStructures::MeshVertex<void> MockVertexNoData;

TEST(MeshVertexTest, InitTest)
{
	Vector3d position(0.0, 0.0, 0.0);
	MockVertexData data(0, Vector3d(1.0, 0.0, 0.0));
	ASSERT_NO_THROW({MockVertex vertex(position, data);});

	/// Check that we can also create a vertex with no data
	ASSERT_NO_THROW({MockVertexNoData vertex(position);});
}

TEST(MeshVertexTest, VertexTest)
{
	Vector3d position(1.0, 2.0, 3.0);
	MockVertexData data(2, Vector3d(1.0, 0.0, 0.0));
	MockVertex vertex(position, data);

	EXPECT_EQ(position, vertex.position);
	EXPECT_EQ(data, vertex.data);

	{
		const MockVertexData& data = vertex.data;
		EXPECT_EQ(2, data.getId());
		EXPECT_EQ(Vector3d(1.0, 0.0, 0.0), data.getNormal());
	}
}

TEST(MeshVertexTest, VertexNoDataTest)
{
	Vector3d position(1.0, 2.0, 3.0);
	MockVertexNoData vertex(position);

	EXPECT_EQ(position, vertex.position);
}<|endoftext|>