<commit_before>#include <algorithm>
#include <cmath>
#include <iostream>

#include <QPainter>
#include <QPaintEvent>
#include <QPoint>
#include <QPointF>
#include <QPolygonF>
#include <QRect>
#include <QStylePainter>
#include <QVector>

#include "tattoo_canvas.h"

static double PI = 3.1415926535;

static double deg2rad(double angle) {
    return angle / 180.0 * PI;
}

static double rad2deg(double angle) {
    return angle / PI * 180.0;
}

TattooCanvas::TattooCanvas(QWidget *parent) {
    revolution = 180.0;
    stroke = 1;
    curveRadius = 30;
    markingsVisible = false;

    setMinimumSize(400, 400);
}

void TattooCanvas::setCurveRadius(int radius) {
    this->curveRadius = radius;

    update();
}

void TattooCanvas::setStroke(int stroke) {
    this->stroke = stroke;

    std::cout << "New stroke is " << stroke << std::endl;

    update();
}

void TattooCanvas::setMarkingsVisible(int enableMarkings) {
    markingsVisible = enableMarkings == Qt::Checked;

    update();
}

double TattooCanvas::computeSpiralRadius(double angle) {
    double a = 0;
    double b = (getRadius() + getOriginOffset() - a) / deg2rad(revolution);
    return a + b * angle;

}

QPointF TattooCanvas::convertToCartesian(double angle, double radius) {
    return QPointF(std::cos(angle) * radius, std::sin(angle) * radius);

}

void TattooCanvas::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QPen pen(Qt::black, stroke, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing);

    int radius = (std::min(width(), height()) - (2 * Margin)) / 2;
    QPoint center(width() / 2, height() / 2);
    painter.drawEllipse(center, radius, radius);

    if (markingsVisible) {
        drawCustomLayer(&painter);
    }
    drawCircles(&painter);
}

void TattooCanvas::drawCircles(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y1 = 2.0 / 3.0 * tHeight;
    double y2 = y1 - tHeight;

    //painter->drawEllipse(QPoint(0, y1), radius, radius);
    painter->drawArc(0 - curveRadius, y1 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 60 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(radius, y2), radius, radius);
    painter->drawArc(0, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 180 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(-radius, y2), radius, radius);
    painter->drawArc(0 - 2.0 * curveRadius, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 0, -60 * 16);

    painter->translate(0, y2);
    int tatRadius = (std::min(width(), height()) - (2 * Margin)) / 2;
    drawSpiral(painter, tatRadius - y2, 270);

    double xOffset = (1.0 / 3.0 * tHeight) * std::cos(deg2rad(30.0));
    double yOffset = (1.0 / 3.0 * tHeight) * std::sin(deg2rad(30.0));

    painter->translate(xOffset, y1 - yOffset);
    drawSpiral(painter, tatRadius - y2, 30);

    painter->translate(-2.0 * xOffset, 0);
    drawSpiral(painter, tatRadius - y2, 150);

    painter->resetTransform();
}

void TattooCanvas::drawCustomLayer(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);
    QPen originalPen = painter->pen();
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y = 1.0 / 3.0 * tHeight;

    int radius = curveRadius - (stroke / 2);
    painter->translate(-curveRadius, -y);
    painter->drawEllipse(QPoint(0, 0), radius, radius);
    painter->drawPie(-radius, -radius, 2 * radius, 2 * radius, 0 * 16, -60 * 16);
    painter->setPen(QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawPoint(0, 0);
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    // Draw curve angle
    painter->drawPie(-10, -10, 20, 20, 0 * 16, -60 * 16);
    QChar phi(0x03D5);
    int charWidth = painter->fontMetrics().width(phi);
    int charHeight = painter->fontMetrics().height();
    painter->drawText(charWidth, charHeight - 3, QString(phi));

    // Add visible theta & r guides
    painter->translate(curveRadius, y);
    painter->translate(0, 2 * y - tHeight);
    painter->drawLine(0, 0, 0, -50);
    painter->rotate(270);
    painter->setPen(QPen(Qt::gray, 1, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin));
    int maxAngle = 120;
    for (int angle = 30; angle <= maxAngle; angle += 10) {
        double r = computeSpiralRadius(deg2rad(angle)) - stroke / 2;
        QPointF pointOnSpiral = convertToCartesian(deg2rad(angle), r);
        if (angle == maxAngle) {
            painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        }
        painter->drawLine(QPointF(0, 0), pointOnSpiral);
    }
    painter->drawArc(-40, -40, 80, 80, 0, -maxAngle * 16);
    painter->rotate(-270);

    // recenter transform
    painter->translate(0, -2 * y + tHeight);
    for (int i = 0; i < 360; i += 90) {
        painter->rotate(i);
        int x = getRadius() + stroke / 2 + 2;
        painter->drawLine(x, 0, x + 5, 0);
        painter->rotate(-i);
    }

    painter->setPen(originalPen);
    painter->resetTransform();
}

void TattooCanvas::drawSpiral(QPainter *painter, int radius, int rotate) {
    double a = 0;
    double b = (radius - a) / deg2rad(revolution);
    double angle = 0.0;
    double r = 0.0;

    QVector<QPointF> points;
    if (!(a > 0)) {
        //points.append(QPointF(width() / 2, height() / 2));
    }

    while (r < radius) {
        r = a + b * angle;
        if (r > radius) {
            r = radius;
            angle = r / (a + b);
        }

        points.append(convertToCartesian(angle, r));

        angle += 0.1;
    };
    QPolygonF polyline(points);
    painter->rotate(rotate);
    painter->drawPolyline(polyline);
    painter->rotate(-rotate);
}

int TattooCanvas::getOriginOffset() const {
    return std::sqrt(3.0 * std::pow((double) curveRadius, 2.0)) / 3.0;
}

int TattooCanvas::getRadius() const {
    return (std::min(width(), height()) - (2 * Margin)) / 2;
}

QPointF TattooCanvas::rotatePoint(const QPointF &point, int angle) {
    double radians = deg2rad(angle);
    return QPointF(
            point.x() * std::cos(radians) - point.y() * std::sin(radians),
            point.x() * std::sin(radians) + point.y() * std::cos(radians)
    );
}

void TattooCanvas::refreshCanvas() {

}

<commit_msg>added formula and 0 axis<commit_after>#include <algorithm>
#include <cmath>
#include <iostream>

#include <QPainter>
#include <QPaintEvent>
#include <QPoint>
#include <QPointF>
#include <QPolygonF>
#include <QRect>
#include <QStylePainter>
#include <QVector>

#include "tattoo_canvas.h"

static double PI = 3.1415926535;

static double deg2rad(double angle) {
    return angle / 180.0 * PI;
}

static double rad2deg(double angle) {
    return angle / PI * 180.0;
}

TattooCanvas::TattooCanvas(QWidget *parent) {
    revolution = 180.0;
    stroke = 1;
    curveRadius = 30;
    markingsVisible = false;

    setMinimumSize(400, 400);
}

void TattooCanvas::setCurveRadius(int radius) {
    this->curveRadius = radius;

    update();
}

void TattooCanvas::setStroke(int stroke) {
    this->stroke = stroke;

    std::cout << "New stroke is " << stroke << std::endl;

    update();
}

void TattooCanvas::setMarkingsVisible(int enableMarkings) {
    markingsVisible = enableMarkings == Qt::Checked;

    update();
}

double TattooCanvas::computeSpiralRadius(double angle) {
    double a = 0;
    double b = (getRadius() + getOriginOffset() - a) / deg2rad(revolution);
    return a + b * angle;

}

QPointF TattooCanvas::convertToCartesian(double angle, double radius) {
    return QPointF(std::cos(angle) * radius, std::sin(angle) * radius);

}

void TattooCanvas::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QPen pen(Qt::black, stroke, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing);

    int radius = (std::min(width(), height()) - (2 * Margin)) / 2;
    QPoint center(width() / 2, height() / 2);
    painter.drawEllipse(center, radius, radius);

    if (markingsVisible) {
        drawCustomLayer(&painter);
    }
    drawCircles(&painter);
}

void TattooCanvas::drawCircles(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y1 = 2.0 / 3.0 * tHeight;
    double y2 = y1 - tHeight;

    //painter->drawEllipse(QPoint(0, y1), radius, radius);
    painter->drawArc(0 - curveRadius, y1 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 60 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(radius, y2), radius, radius);
    painter->drawArc(0, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 180 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(-radius, y2), radius, radius);
    painter->drawArc(0 - 2.0 * curveRadius, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 0, -60 * 16);

    painter->translate(0, y2);
    int tatRadius = (std::min(width(), height()) - (2 * Margin)) / 2;
    drawSpiral(painter, tatRadius - y2, 270);

    double xOffset = (1.0 / 3.0 * tHeight) * std::cos(deg2rad(30.0));
    double yOffset = (1.0 / 3.0 * tHeight) * std::sin(deg2rad(30.0));

    painter->translate(xOffset, y1 - yOffset);
    drawSpiral(painter, tatRadius - y2, 30);

    painter->translate(-2.0 * xOffset, 0);
    drawSpiral(painter, tatRadius - y2, 150);

    painter->resetTransform();
}

void TattooCanvas::drawCustomLayer(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);
    QPen originalPen = painter->pen();
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y = 1.0 / 3.0 * tHeight;

    int radius = curveRadius - (stroke / 2);
    painter->translate(-curveRadius, -y);
    painter->drawEllipse(QPoint(0, 0), radius, radius);
    painter->drawPie(-radius, -radius, 2 * radius, 2 * radius, 0 * 16, -60 * 16);
    painter->setPen(QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawPoint(0, 0);
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    // Draw curve angle
    painter->drawPie(-10, -10, 20, 20, 0 * 16, -60 * 16);
    QChar phi(0x03D5);
    int charWidth = painter->fontMetrics().width(phi);
    int charHeight = painter->fontMetrics().height();
    painter->drawText(charWidth, charHeight - 3, QString(phi));

    // Add visible theta & r guides
    painter->translate(curveRadius, y);
    painter->translate(0, 2 * y - tHeight);
    painter->drawLine(0, 0, 0, -50);
    painter->rotate(270);
    painter->setPen(QPen(Qt::gray, 1, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin));
    int maxAngle = 120;
    for (int angle = 30; angle <= maxAngle; angle += 10) {
        double r = computeSpiralRadius(deg2rad(angle)) - stroke / 2;
        QPointF pointOnSpiral = convertToCartesian(deg2rad(angle), r);
        if (angle == maxAngle) {
            painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        }
        painter->drawLine(QPointF(0, 0), pointOnSpiral);
    }
    painter->drawArc(-40, -40, 80, 80, 0, -maxAngle * 16);
    painter->rotate(-270);
    QChar theta(0x03F4);
    painter->drawText(40 + charWidth / 2, 0, theta);
    painter->drawText(60, 50, "r");

    // recenter transform
    painter->translate(0, -2 * y + tHeight);
    QString formula = QString("r = a + b") + theta;
    formula.append('\n');
    formula.append("a = 0\n");
    formula.append(QString("b = l / ") + QChar(0x03C0));
    painter->drawText(15, -120, 100, 100, Qt::AlignLeft | Qt::TextWordWrap, formula);

    painter->save();
    painter->setPen(QPen(Qt::gray, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawLine(0, 0, getRadius(), 0);
    painter->restore();
    painter->drawText(getRadius() - 40, -2, "l");

    for (int i = 0; i < 360; i += 90) {
        painter->rotate(i);
        int x = getRadius() + stroke / 2 + 2;
        painter->drawLine(x, 0, x + 5, 0);
        painter->rotate(-i);
    }

    painter->setPen(originalPen);
    painter->resetTransform();
}

void TattooCanvas::drawSpiral(QPainter *painter, int radius, int rotate) {
    double a = 0;
    double b = (radius - a) / deg2rad(revolution);
    double angle = 0.0;
    double r = 0.0;

    QVector<QPointF> points;
    if (!(a > 0)) {
        //points.append(QPointF(width() / 2, height() / 2));
    }

    while (r < radius) {
        r = a + b * angle;
        if (r > radius) {
            r = radius;
            angle = r / (a + b);
        }

        points.append(convertToCartesian(angle, r));

        angle += 0.1;
    };
    QPolygonF polyline(points);
    painter->rotate(rotate);
    painter->drawPolyline(polyline);
    painter->rotate(-rotate);
}

int TattooCanvas::getOriginOffset() const {
    return std::sqrt(3.0 * std::pow((double) curveRadius, 2.0)) / 3.0;
}

int TattooCanvas::getRadius() const {
    return (std::min(width(), height()) - (2 * Margin)) / 2;
}

QPointF TattooCanvas::rotatePoint(const QPointF &point, int angle) {
    double radians = deg2rad(angle);
    return QPointF(
            point.x() * std::cos(radians) - point.y() * std::sin(radians),
            point.x() * std::sin(radians) + point.y() * std::cos(radians)
    );
}

void TattooCanvas::refreshCanvas() {

}

<|endoftext|>


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

#include "base/message_pump_x.h"

#include <X11/extensions/XInput2.h>

#include "base/basictypes.h"
#include "base/message_loop.h"

#if defined(TOOLKIT_USES_GTK)
#include <gdk/gdkx.h>
#endif

namespace {

gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
  if (XPending(base::MessagePumpX::GetDefaultXDisplay()))
    *timeout_ms = 0;
  else
    *timeout_ms = -1;
  return FALSE;
}

gboolean XSourceCheck(GSource* source) {
  return XPending(base::MessagePumpX::GetDefaultXDisplay());
}

gboolean XSourceDispatch(GSource* source,
                         GSourceFunc unused_func,
                         gpointer unused_data) {
  // TODO(sad): When GTK event proecssing is completely removed, the event
  // processing and dispatching should be done here (i.e. XNextEvent,
  // ProcessXEvent etc.)
  return TRUE;
}

GSourceFuncs XSourceFuncs = {
  XSourcePrepare,
  XSourceCheck,
  XSourceDispatch,
  NULL
};

// The opcode used for checking events.
int xiopcode = -1;

#if defined(TOOLKIT_USES_GTK)
gboolean PlaceholderDispatch(GSource* source,
                             GSourceFunc cb,
                             gpointer data) {
  return TRUE;
}
#else
// If the GTK/GDK event processing is not present, the message-pump opens a
// connection to the display and owns it.
Display* g_xdisplay = NULL;
#endif  // defined(TOOLKIT_USES_GTK)

void InitializeXInput2(void) {
  Display* display = base::MessagePumpX::GetDefaultXDisplay();
  if (!display)
    return;

  int event, err;

  if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
    VLOG(1) << "X Input extension not available.";
    xiopcode = -1;
    return;
  }

#if defined(USE_XI2_MT)
  // USE_XI2_MT also defines the required XI2 minor minimum version.
  int major = 2, minor = USE_XI2_MT;
#else
  int major = 2, minor = 0;
#endif
  if (XIQueryVersion(display, &major, &minor) == BadRequest) {
    VLOG(1) << "XInput2 not supported in the server.";
    xiopcode = -1;
    return;
  }
#if defined(USE_XI2_MT)
  if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
    VLOG(1) << "XI version on server is " << major << "." << minor << ". "
            << "But 2." << USE_XI2_MT << " is required.";
    xiopcode = -1;
    return;
  }
#endif
}

}  // namespace

namespace base {

MessagePumpX::MessagePumpX() : MessagePumpGlib(),
#if defined(TOOLKIT_USES_GTK)
    gdksource_(NULL),
    dispatching_event_(false),
    capture_x_events_(0),
    capture_gdk_events_(0),
#endif
    x_source_(NULL) {
  InitializeXInput2();
#if defined(TOOLKIT_USES_GTK)
  gdk_window_add_filter(NULL, &GdkEventFilter, this);
  gdk_event_handler_set(&EventDispatcherX, this, NULL);
  InitializeEventsToCapture();
#else
  InitXSource();
#endif
}

MessagePumpX::~MessagePumpX() {
#if defined(TOOLKIT_USES_GTK)
  gdk_window_remove_filter(NULL, &GdkEventFilter, this);
  gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event),
                        this, NULL);
#else
  g_source_destroy(x_source_);
  g_source_unref(x_source_);
  XCloseDisplay(g_xdisplay);
  g_xdisplay = NULL;
#endif
}

// static
Display* MessagePumpX::GetDefaultXDisplay() {
#if defined(TOOLKIT_USES_GTK)
  static GdkDisplay* display = gdk_display_get_default();
  return display ? GDK_DISPLAY_XDISPLAY(display) : NULL;
#else
  if (!g_xdisplay)
    g_xdisplay = XOpenDisplay(NULL);
  return g_xdisplay;
#endif
}

// static
bool MessagePumpX::HasXInput2() {
  return xiopcode != -1;
}

void MessagePumpX::InitXSource() {
  DCHECK(!x_source_);
  GPollFD* x_poll = new GPollFD();
  x_poll->fd = ConnectionNumber(GetDefaultXDisplay());
  x_poll->events = G_IO_IN;

  x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
  g_source_add_poll(x_source_, x_poll);
  g_source_set_can_recurse(x_source_, FALSE);
  g_source_attach(x_source_, g_main_context_default());
}

bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) {
  return
#if defined(TOOLKIT_USES_GTK)
      capture_x_events_[xev->type] &&
#endif
      (xev->type != GenericEvent || xev->xcookie.extension == xiopcode);
}

bool MessagePumpX::ProcessXEvent(XEvent* xev) {
  bool should_quit = false;

  bool have_cookie = false;
  if (xev->type == GenericEvent &&
      XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
    have_cookie = true;
  }

  if (WillProcessXEvent(xev) == EVENT_CONTINUE) {
    MessagePumpDispatcher::DispatchStatus status =
        GetDispatcher()->Dispatch(xev);

    if (status == MessagePumpDispatcher::EVENT_QUIT) {
      should_quit = true;
      Quit();
    } else if (status == MessagePumpDispatcher::EVENT_IGNORED) {
      VLOG(1) << "Event (" << xev->type << ") not handled.";
    }
    DidProcessXEvent(xev);
  }

  if (have_cookie) {
    XFreeEventData(xev->xgeneric.display, &xev->xcookie);
  }

  return should_quit;
}

bool MessagePumpX::RunOnce(GMainContext* context, bool block) {
  Display* display = GetDefaultXDisplay();
  if (!display || !GetDispatcher())
    return g_main_context_iteration(context, block);

  if (XPending(display)) {
    XEvent xev;
    XPeekEvent(display, &xev);

    if (ShouldCaptureXEvent(&xev)) {
      XNextEvent(display, &xev);
      if (ProcessXEvent(&xev))
        return true;
#if defined(TOOLKIT_USES_GTK)
    } else if (gdksource_) {
      // TODO(sad): A couple of extra events can still sneak in during this.
      // Those should be sent back to the X queue from the dispatcher
      // EventDispatcherX.
      gdksource_->source_funcs->dispatch = gdkdispatcher_;
      g_main_context_iteration(context, FALSE);
#endif
    }
  }

  bool retvalue;
#if defined(TOOLKIT_USES_GTK)
  if (gdksource_) {
    // Replace the dispatch callback of the GDK event source temporarily so that
    // it doesn't read events from X.
    gboolean (*cb)(GSource*, GSourceFunc, void*) =
        gdksource_->source_funcs->dispatch;
    gdksource_->source_funcs->dispatch = PlaceholderDispatch;

    dispatching_event_ = true;
    retvalue = g_main_context_iteration(context, block);
    dispatching_event_ = false;

    gdksource_->source_funcs->dispatch = cb;
  } else {
    retvalue = g_main_context_iteration(context, block);
  }
#else
  retvalue = g_main_context_iteration(context, block);
#endif

  return retvalue;
}

bool MessagePumpX::WillProcessXEvent(XEvent* xevent) {
  ObserverListBase<MessagePumpObserver>::Iterator it(observers());
  MessagePumpObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    if (obs->WillProcessEvent(xevent))
      return true;
  }
  return false;
}

void MessagePumpX::DidProcessXEvent(XEvent* xevent) {
  ObserverListBase<MessagePumpObserver>::Iterator it(observers());
  MessagePumpObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    obs->DidProcessEvent(xevent);
  }
}

#if defined(TOOLKIT_USES_GTK)
GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent,
                                             GdkEvent* gevent,
                                             gpointer data) {
  MessagePumpX* pump = static_cast<MessagePumpX*>(data);
  XEvent* xev = static_cast<XEvent*>(gxevent);

  if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) {
    pump->ProcessXEvent(xev);
    return GDK_FILTER_REMOVE;
  }
  return GDK_FILTER_CONTINUE;
}

void MessagePumpX::EventDispatcherX(GdkEvent* event, gpointer data) {
  MessagePumpX* pump_x = reinterpret_cast<MessagePumpX*>(data);
  if (!pump_x->gdksource_) {
    pump_x->gdksource_ = g_main_current_source();
    if (pump_x->gdksource_)
      pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
  } else if (!pump_x->IsDispatchingEvent()) {
    if (event->type != GDK_NOTHING &&
        pump_x->capture_gdk_events_[event->type]) {
      NOTREACHED() << "GDK received an event it shouldn't have:" << event->type;
    }
  }

  gtk_main_do_event(event);
}

void MessagePumpX::InitializeEventsToCapture(void) {
  // TODO(sad): Decide which events we want to capture and update the tables
  // accordingly.
  capture_x_events_[KeyPress] = true;
  capture_gdk_events_[GDK_KEY_PRESS] = true;

  capture_x_events_[KeyRelease] = true;
  capture_gdk_events_[GDK_KEY_RELEASE] = true;

  capture_x_events_[ButtonPress] = true;
  capture_gdk_events_[GDK_BUTTON_PRESS] = true;

  capture_x_events_[ButtonRelease] = true;
  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;

  capture_x_events_[MotionNotify] = true;
  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;

  capture_x_events_[GenericEvent] = true;
}

COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small);

#endif  // defined(TOOLKIT_USES_GTK)

}  // namespace base
<commit_msg>aura: Make MessagePumpX check that X connection is open.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_pump_x.h"

#include <X11/extensions/XInput2.h>

#include "base/basictypes.h"
#include "base/message_loop.h"

#if defined(TOOLKIT_USES_GTK)
#include <gdk/gdkx.h>
#endif

namespace {

gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
  if (XPending(base::MessagePumpX::GetDefaultXDisplay()))
    *timeout_ms = 0;
  else
    *timeout_ms = -1;
  return FALSE;
}

gboolean XSourceCheck(GSource* source) {
  return XPending(base::MessagePumpX::GetDefaultXDisplay());
}

gboolean XSourceDispatch(GSource* source,
                         GSourceFunc unused_func,
                         gpointer unused_data) {
  // TODO(sad): When GTK event proecssing is completely removed, the event
  // processing and dispatching should be done here (i.e. XNextEvent,
  // ProcessXEvent etc.)
  return TRUE;
}

GSourceFuncs XSourceFuncs = {
  XSourcePrepare,
  XSourceCheck,
  XSourceDispatch,
  NULL
};

// The opcode used for checking events.
int xiopcode = -1;

#if defined(TOOLKIT_USES_GTK)
gboolean PlaceholderDispatch(GSource* source,
                             GSourceFunc cb,
                             gpointer data) {
  return TRUE;
}
#else
// If the GTK/GDK event processing is not present, the message-pump opens a
// connection to the display and owns it.
Display* g_xdisplay = NULL;
#endif  // defined(TOOLKIT_USES_GTK)

void InitializeXInput2(void) {
  Display* display = base::MessagePumpX::GetDefaultXDisplay();
  if (!display)
    return;

  int event, err;

  if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
    VLOG(1) << "X Input extension not available.";
    xiopcode = -1;
    return;
  }

#if defined(USE_XI2_MT)
  // USE_XI2_MT also defines the required XI2 minor minimum version.
  int major = 2, minor = USE_XI2_MT;
#else
  int major = 2, minor = 0;
#endif
  if (XIQueryVersion(display, &major, &minor) == BadRequest) {
    VLOG(1) << "XInput2 not supported in the server.";
    xiopcode = -1;
    return;
  }
#if defined(USE_XI2_MT)
  if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
    VLOG(1) << "XI version on server is " << major << "." << minor << ". "
            << "But 2." << USE_XI2_MT << " is required.";
    xiopcode = -1;
    return;
  }
#endif
}

}  // namespace

namespace base {

MessagePumpX::MessagePumpX() : MessagePumpGlib(),
#if defined(TOOLKIT_USES_GTK)
    gdksource_(NULL),
    dispatching_event_(false),
    capture_x_events_(0),
    capture_gdk_events_(0),
#endif
    x_source_(NULL) {
  InitializeXInput2();
#if defined(TOOLKIT_USES_GTK)
  gdk_window_add_filter(NULL, &GdkEventFilter, this);
  gdk_event_handler_set(&EventDispatcherX, this, NULL);
  InitializeEventsToCapture();
#else
  InitXSource();
#endif
}

MessagePumpX::~MessagePumpX() {
#if defined(TOOLKIT_USES_GTK)
  gdk_window_remove_filter(NULL, &GdkEventFilter, this);
  gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event),
                        this, NULL);
#else
  g_source_destroy(x_source_);
  g_source_unref(x_source_);
  XCloseDisplay(g_xdisplay);
  g_xdisplay = NULL;
#endif
}

// static
Display* MessagePumpX::GetDefaultXDisplay() {
#if defined(TOOLKIT_USES_GTK)
  static GdkDisplay* display = gdk_display_get_default();
  return display ? GDK_DISPLAY_XDISPLAY(display) : NULL;
#else
  if (!g_xdisplay)
    g_xdisplay = XOpenDisplay(NULL);
  return g_xdisplay;
#endif
}

// static
bool MessagePumpX::HasXInput2() {
  return xiopcode != -1;
}

void MessagePumpX::InitXSource() {
  DCHECK(!x_source_);
  GPollFD* x_poll = new GPollFD();
  Display* display = GetDefaultXDisplay();
  CHECK(display) << "Unable to get connection to X server";
  x_poll->fd = ConnectionNumber(display);
  x_poll->events = G_IO_IN;

  x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
  g_source_add_poll(x_source_, x_poll);
  g_source_set_can_recurse(x_source_, FALSE);
  g_source_attach(x_source_, g_main_context_default());
}

bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) {
  return
#if defined(TOOLKIT_USES_GTK)
      capture_x_events_[xev->type] &&
#endif
      (xev->type != GenericEvent || xev->xcookie.extension == xiopcode);
}

bool MessagePumpX::ProcessXEvent(XEvent* xev) {
  bool should_quit = false;

  bool have_cookie = false;
  if (xev->type == GenericEvent &&
      XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
    have_cookie = true;
  }

  if (WillProcessXEvent(xev) == EVENT_CONTINUE) {
    MessagePumpDispatcher::DispatchStatus status =
        GetDispatcher()->Dispatch(xev);

    if (status == MessagePumpDispatcher::EVENT_QUIT) {
      should_quit = true;
      Quit();
    } else if (status == MessagePumpDispatcher::EVENT_IGNORED) {
      VLOG(1) << "Event (" << xev->type << ") not handled.";
    }
    DidProcessXEvent(xev);
  }

  if (have_cookie) {
    XFreeEventData(xev->xgeneric.display, &xev->xcookie);
  }

  return should_quit;
}

bool MessagePumpX::RunOnce(GMainContext* context, bool block) {
  Display* display = GetDefaultXDisplay();
  if (!display || !GetDispatcher())
    return g_main_context_iteration(context, block);

  if (XPending(display)) {
    XEvent xev;
    XPeekEvent(display, &xev);

    if (ShouldCaptureXEvent(&xev)) {
      XNextEvent(display, &xev);
      if (ProcessXEvent(&xev))
        return true;
#if defined(TOOLKIT_USES_GTK)
    } else if (gdksource_) {
      // TODO(sad): A couple of extra events can still sneak in during this.
      // Those should be sent back to the X queue from the dispatcher
      // EventDispatcherX.
      gdksource_->source_funcs->dispatch = gdkdispatcher_;
      g_main_context_iteration(context, FALSE);
#endif
    }
  }

  bool retvalue;
#if defined(TOOLKIT_USES_GTK)
  if (gdksource_) {
    // Replace the dispatch callback of the GDK event source temporarily so that
    // it doesn't read events from X.
    gboolean (*cb)(GSource*, GSourceFunc, void*) =
        gdksource_->source_funcs->dispatch;
    gdksource_->source_funcs->dispatch = PlaceholderDispatch;

    dispatching_event_ = true;
    retvalue = g_main_context_iteration(context, block);
    dispatching_event_ = false;

    gdksource_->source_funcs->dispatch = cb;
  } else {
    retvalue = g_main_context_iteration(context, block);
  }
#else
  retvalue = g_main_context_iteration(context, block);
#endif

  return retvalue;
}

bool MessagePumpX::WillProcessXEvent(XEvent* xevent) {
  ObserverListBase<MessagePumpObserver>::Iterator it(observers());
  MessagePumpObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    if (obs->WillProcessEvent(xevent))
      return true;
  }
  return false;
}

void MessagePumpX::DidProcessXEvent(XEvent* xevent) {
  ObserverListBase<MessagePumpObserver>::Iterator it(observers());
  MessagePumpObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    obs->DidProcessEvent(xevent);
  }
}

#if defined(TOOLKIT_USES_GTK)
GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent,
                                             GdkEvent* gevent,
                                             gpointer data) {
  MessagePumpX* pump = static_cast<MessagePumpX*>(data);
  XEvent* xev = static_cast<XEvent*>(gxevent);

  if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) {
    pump->ProcessXEvent(xev);
    return GDK_FILTER_REMOVE;
  }
  return GDK_FILTER_CONTINUE;
}

void MessagePumpX::EventDispatcherX(GdkEvent* event, gpointer data) {
  MessagePumpX* pump_x = reinterpret_cast<MessagePumpX*>(data);
  if (!pump_x->gdksource_) {
    pump_x->gdksource_ = g_main_current_source();
    if (pump_x->gdksource_)
      pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
  } else if (!pump_x->IsDispatchingEvent()) {
    if (event->type != GDK_NOTHING &&
        pump_x->capture_gdk_events_[event->type]) {
      NOTREACHED() << "GDK received an event it shouldn't have:" << event->type;
    }
  }

  gtk_main_do_event(event);
}

void MessagePumpX::InitializeEventsToCapture(void) {
  // TODO(sad): Decide which events we want to capture and update the tables
  // accordingly.
  capture_x_events_[KeyPress] = true;
  capture_gdk_events_[GDK_KEY_PRESS] = true;

  capture_x_events_[KeyRelease] = true;
  capture_gdk_events_[GDK_KEY_RELEASE] = true;

  capture_x_events_[ButtonPress] = true;
  capture_gdk_events_[GDK_BUTTON_PRESS] = true;

  capture_x_events_[ButtonRelease] = true;
  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;

  capture_x_events_[MotionNotify] = true;
  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;

  capture_x_events_[GenericEvent] = true;
}

COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small);

#endif  // defined(TOOLKIT_USES_GTK)

}  // namespace base
<|endoftext|>


<commit_before>// Day17.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef std::pair<size_t, size_t> Coordinate;
typedef std::pair<Coordinate, std::string> Position;

constexpr size_t GridSize = 4;

std::string GetPath(const Coordinate & Start, const Coordinate & Destination, const std::string & Prefix);
void GetDoorStatus(const std::string & Hash, bool & Up, bool & Down, bool & Left, bool & Right);

int main()
{
	const std::string Input = "rrrbmfta";

	std::cout << "Path: " << GetPath(Coordinate(0, 0), Coordinate(3, 3), Input) << std::endl;

	system("pause");

    return 0;
}

size_t GetDistance(const Coordinate & Position, const Coordinate & Destination)
{
	int64_t dX = Destination.first - Position.first;
	int64_t dY = Destination.second - Position.second;

	return std::abs(dX) + std::abs(dY);
}

size_t GetHeuristic(const Coordinate & Position, const Coordinate & Destination, const std::string & Path)
{
	return GetDistance(Position, Destination) + Path.size();
}

void AddToList(std::multimap<size_t, Position> & OpenList, const Coordinate & Position, const Coordinate & Destination, const std::string & Path)
{
	OpenList.insert({ GetHeuristic(Position, Destination, Path), { Position, Path } });
}

std::string GetPath(const Coordinate & Start, const Coordinate & Destination, const std::string & Prefix)
{
	std::multimap<size_t, Position> OpenList = { { GetDistance(Start, Destination), { Start, "" } } };

	while (!OpenList.empty())
	{
		Position Node = OpenList.begin()->second;
		OpenList.erase(OpenList.begin());

		if (Node.first == Destination)
		{
			return Node.second;
		}

		bool Up, Down, Left, Right;
		GetDoorStatus(Prefix + Node.second, Up, Down, Left, Right);

		if (Up && (Node.first.second > 0))
		{
			AddToList(OpenList, { Node.first.first, Node.first.second - 1 }, Destination, Node.second + "U");
		}

		if (Down && (Node.first.second < GridSize - 1))
		{
			AddToList(OpenList, { Node.first.first, Node.first.second + 1 }, Destination, Node.second + "D");
		}

		if (Left && (Node.first.first > 0))
		{
			AddToList(OpenList, { Node.first.first - 1, Node.first.second }, Destination, Node.second + "L");
		}

		if (Right && (Node.first.first < GridSize - 1))
		{
			AddToList(OpenList, { Node.first.first + 1, Node.first.second }, Destination, Node.second + "R");
		}
	}

	return std::string();
}

void GetDoorStatus(const std::string & Hash, bool & Up, bool & Down, bool & Left, bool & Right)
{
	MD5 Hasher;
	MD5::Hash Result = Hasher.Compute(ByteVector(Hash.begin(), Hash.end()));

	Up = ((Result[0] & 0xF0) > 0xA0) ? true : false;
	Down = ((Result[0] & 0x0F) > 0x0A) ? true : false;

	Left = ((Result[1] & 0xF0) > 0xA0) ? true : false;
	Right = ((Result[1] & 0x0F) > 0x0A) ? true : false;
}<commit_msg>Day 17 part two<commit_after>// Day17.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef std::pair<size_t, size_t> Coordinate;
typedef std::pair<Coordinate, std::string> Position;

constexpr size_t GridSize = 4;

std::string GetPath(const Coordinate & Start, const Coordinate & Destination, const std::string & Prefix, bool Longest);
void GetDoorStatus(const std::string & Hash, bool & Up, bool & Down, bool & Left, bool & Right);

int main()
{
	const std::string Input = "rrrbmfta";

	std::cout << "Part One: " << GetPath(Coordinate(0, 0), Coordinate(3, 3), Input, false) << std::endl;
	std::cout << "Part Two: " << GetPath(Coordinate(0, 0), Coordinate(3, 3), Input, true).size() << std::endl;

	system("pause");

    return 0;
}

size_t GetDistance(const Coordinate & Position, const Coordinate & Destination)
{
	int64_t dX = Destination.first - Position.first;
	int64_t dY = Destination.second - Position.second;

	return std::abs(dX) + std::abs(dY);
}

size_t GetHeuristic(const Coordinate & Position, const Coordinate & Destination, const std::string & Path)
{
	return GetDistance(Position, Destination) + Path.size();
}

void AddToList(std::multimap<size_t, Position> & OpenList, const Coordinate & Position, const Coordinate & Destination, const std::string & Path)
{
	OpenList.insert({ GetHeuristic(Position, Destination, Path), { Position, Path } });
}

std::string GetPath(const Coordinate & Start, const Coordinate & Destination, const std::string & Prefix, bool Longest)
{
	std::multimap<size_t, Position> OpenList = { { GetDistance(Start, Destination), { Start, "" } } };

	std::string LongPath;

	while (!OpenList.empty())
	{
		Position Node = OpenList.begin()->second;
		OpenList.erase(OpenList.begin());

		if (Node.first == Destination)
		{
			if (!Longest)
			{
				return Node.second;
			}
			else
			{
				if (LongPath.size() < Node.second.size())
				{
					LongPath = Node.second;
				}
				continue;
			}
		}

		bool Up, Down, Left, Right;
		GetDoorStatus(Prefix + Node.second, Up, Down, Left, Right);

		if (Up && (Node.first.second > 0))
		{
			AddToList(OpenList, { Node.first.first, Node.first.second - 1 }, Destination, Node.second + "U");
		}

		if (Down && (Node.first.second < GridSize - 1))
		{
			AddToList(OpenList, { Node.first.first, Node.first.second + 1 }, Destination, Node.second + "D");
		}

		if (Left && (Node.first.first > 0))
		{
			AddToList(OpenList, { Node.first.first - 1, Node.first.second }, Destination, Node.second + "L");
		}

		if (Right && (Node.first.first < GridSize - 1))
		{
			AddToList(OpenList, { Node.first.first + 1, Node.first.second }, Destination, Node.second + "R");
		}
	}

	return LongPath;
}

void GetDoorStatus(const std::string & Hash, bool & Up, bool & Down, bool & Left, bool & Right)
{
	MD5 Hasher;
	MD5::Hash Result = Hasher.Compute(ByteVector(Hash.begin(), Hash.end()));

	Up = ((Result[0] & 0xF0) > 0xA0) ? true : false;
	Down = ((Result[0] & 0x0F) > 0x0A) ? true : false;

	Left = ((Result[1] & 0xF0) > 0xA0) ? true : false;
	Right = ((Result[1] & 0x0F) > 0x0A) ? true : false;
}<|endoftext|>


<commit_before>#include "math3d/math3d.h"
#include "pbge/pbge.h"

class MySceneInitializer : public pbge::SceneInitializer {
public:
    pbge::SceneGraph * operator () (pbge::GraphicAPI * gfx, pbge::Window * window) {
        pbge::Renderer * renderer = window->getRenderer();
        renderer->addSceneProcessor(new pbge::RenderPassProcessor);
        renderer->addPostProcessor(new pbge::BlitToFramebuffer);
        pbge::Node * root = new pbge::TransformationNode;
        pbge::SceneGraph * graph = new pbge::SceneGraph(root);

        configureCamera(root, gfx);
        createModel(root, gfx);

        return graph;
    }

private:
    void configureCamera(pbge::Node * parent, pbge::GraphicAPI * gfx) {
        pbge::TransformationNode * cameraParent =
            pbge::TransformationNode::translation(0, 0, 10);
        pbge::CameraNode * camera = new pbge::CameraNode;
        camera->lookAt(math3d::vector4(0,1,0), math3d::vector4(0, 0, -1));
        camera->setPerspective(90, 1.0f, 2.0f, 30.0f);
        cameraParent->addChild(camera);
        parent->addChild(cameraParent);
    }
    void createModel(pbge::Node * parent, pbge::GraphicAPI * gfx) {
        pbge::VBOModel * sphere = pbge::Geometrics::createSphere(2,100,gfx);
        pbge::ModelInstance * model = new pbge::ModelInstance(sphere);
        pbge::GPUProgram * shader = gfx->getFactory()->createProgramFromString(
            "#version 150\n"
            "in vec4 pbge_Vertex;\n"
            "out vec4 color\n;"
            "uniform mat4 pbge_ModelViewProjectionMatrix;\n"
            "void main() {\n"
            "   mat4 scale = mat4(1,0,0,0,\n"
            "                     0,2,0,0,\n"
            "                     0,0,1,0,\n"
            "                     0,0,0,1);\n"
            "   gl_Position = pbge_ModelViewProjectionMatrix*scale*pbge_Vertex;\n"
            "   color = vec4(pbge_Vertex.xyz, 1);\n"
            "}",
            "in vec4 color;\n"
            "void main() {\n"
            "   gl_FragColor = color;\n"
            "}"
            );
        model->setRenderPassProgram(shader);
        parent->addChild(model);
    }
};

int main() {
    pbge::Manager manager;
    MySceneInitializer sceneInitializer;
    manager.setWindowTitle("Ellipsoid demo");
    manager.setWindowDimensions(1024, 768);
    manager.setSceneInitializer(&sceneInitializer);
    manager.displayGraphics();
    return 0;
}<commit_msg>Unused includes<commit_after>#include "pbge/pbge.h"

class MySceneInitializer : public pbge::SceneInitializer {
public:
    pbge::SceneGraph * operator () (pbge::GraphicAPI * gfx, pbge::Window * window) {
        pbge::Renderer * renderer = window->getRenderer();
        renderer->addSceneProcessor(new pbge::RenderPassProcessor);
        renderer->addPostProcessor(new pbge::BlitToFramebuffer);
        pbge::Node * root = new pbge::TransformationNode;
        pbge::SceneGraph * graph = new pbge::SceneGraph(root);

        configureCamera(root, gfx);
        createModel(root, gfx);

        return graph;
    }

private:
    void configureCamera(pbge::Node * parent, pbge::GraphicAPI * gfx) {
        pbge::TransformationNode * cameraParent =
            pbge::TransformationNode::translation(0, 0, 10);
        pbge::CameraNode * camera = new pbge::CameraNode;
        camera->lookAt(math3d::vector4(0,1,0), math3d::vector4(0, 0, -1));
        camera->setPerspective(90, 1.0f, 2.0f, 30.0f);
        cameraParent->addChild(camera);
        parent->addChild(cameraParent);
    }
    void createModel(pbge::Node * parent, pbge::GraphicAPI * gfx) {
        pbge::VBOModel * sphere = pbge::Geometrics::createSphere(2,100,gfx);
        pbge::ModelInstance * model = new pbge::ModelInstance(sphere);
        pbge::GPUProgram * shader = gfx->getFactory()->createProgramFromString(
            "#version 150\n"
            "in vec4 pbge_Vertex;\n"
            "out vec4 color\n;"
            "uniform mat4 pbge_ModelViewProjectionMatrix;\n"
            "void main() {\n"
            "   mat4 scale = mat4(1,0,0,0,\n"
            "                     0,2,0,0,\n"
            "                     0,0,1,0,\n"
            "                     0,0,0,1);\n"
            "   gl_Position = pbge_ModelViewProjectionMatrix*scale*pbge_Vertex;\n"
            "   color = vec4(pbge_Vertex.xyz, 1);\n"
            "}",
            "in vec4 color;\n"
            "void main() {\n"
            "   gl_FragColor = color;\n"
            "}"
            );
        model->setRenderPassProgram(shader);
        parent->addChild(model);
    }
};

int main() {
    pbge::Manager manager;
    MySceneInitializer sceneInitializer;
    manager.setWindowTitle("Ellipsoid demo");
    manager.setWindowDimensions(1024, 768);
    manager.setSceneInitializer(&sceneInitializer);
    manager.displayGraphics();
    return 0;
}<|endoftext|>


<commit_before>#include "dsa/message.h"
#include "dsa/network.h"

#include "../test/sdk/async_test.h"
#include "../test/sdk/test_config.h"

#include "network/tcp/tcp_client.h"
#include "network/tcp/tcp_server.h"

#include <chrono>
#include <ctime>

#define WAIT(wait_time, callback) wait_for_bool((wait_time), (callback))
#define ASYNC(wait_time, strand, callback) \
  wait_for_bool((wait_time), (strand), (callback))

using namespace dsa;

const int SLEEP_INTERVAL = 25;
using high_resolution_clock = std::chrono::high_resolution_clock;
using time_point = std::chrono::high_resolution_clock::time_point;

class MockNode : public NodeModel {
 public:
  std::unique_ptr<SubscribeOptions> first_subscribe_options;
  std::unique_ptr<SubscribeOptions> second_subscribe_options;

  explicit MockNode(LinkStrandRef strand) : NodeModel(std::move(strand)){};

  void on_subscribe(const SubscribeOptions &options) override {
    first_subscribe_options.reset(new SubscribeOptions(options));
    if (_subscribe_callback != nullptr) {
      set_value(Variant("hello"));
    }
  }
};

int main() {
  App app;

  TestConfig server_config(app);

  MockNode *root_node = new MockNode(server_config.strand);

  server_config.get_link_config()->set_stream_acceptor(
      make_unique_<NodeStateManager>(ref_<MockNode>(root_node)));

  WrapperConfig client_config = server_config.get_client_config(app);

  app.async_start(2);

  //  auto tcp_server(new TcpServer(server_config));
  auto tcp_server = make_shared_<TcpServer>(server_config);
  tcp_server->start();

  auto tcp_client = make_shared_<TcpClient>(client_config);
  tcp_client->connect();

  ASYNC(500, (*client_config.strand)(),
        [&]() { return tcp_client->get_session().is_connected(); });

  SubscribeOptions initial_options;
  initial_options.queue_time = 0x1234;
  initial_options.queue_size = 0x5678;

  ref_<const SubscribeResponseMessage> last_response;

  const uint16_t MAX_NUM_MSGS = 0xffff;
  uint16_t idx = 0;
  time_point start_time_point, end_time_point;

  start_time_point = high_resolution_clock::now();
  while (idx < MAX_NUM_MSGS) {
    auto subscribe_stream = tcp_client->get_session().requester.subscribe(
        "",
        [&](ref_<const SubscribeResponseMessage> &&msg,
            IncomingSubscribeStream &stream) {
          if (idx == (MAX_NUM_MSGS - 1)) {
            last_response = std::move(msg);
          }
        },
        initial_options);

    // move out of the loop?
    if (idx == (MAX_NUM_MSGS - 1)) {
      int waited = 0;
      while (waited < MAX_NUM_MSGS * 100) {
        if (last_response != nullptr) {
          end_time_point = high_resolution_clock::now();
          break;
        }

        boost::this_thread::sleep(
            boost::posix_time::milliseconds(SLEEP_INTERVAL));
        waited += SLEEP_INTERVAL;
      }
    }

    idx++;
  }

  std::cout << std::chrono::system_clock::to_time_t(start_time_point) << ", "
            << std::chrono::system_clock::to_time_t(end_time_point) << std::endl
            << std::chrono::duration_cast<std::chrono::milliseconds>(
                   end_time_point - start_time_point)
                   .count()
            << std::endl;

  Server::close_in_strand(tcp_server);
  Client::close_in_strand(tcp_client);

  app.close();

  WAIT(500, [&]() { return app.is_stopped(); });

  if (!app.is_stopped()) {
    app.force_stop();
  }

  app.wait();
}
<commit_msg>fix compilation issuw on Windows platform<commit_after>#include "dsa/message.h"
#include "dsa/network.h"

#include "../test/sdk/async_test.h"
#include "../test/sdk/test_config.h"

#include "network/tcp/tcp_client.h"
#include "network/tcp/tcp_server.h"

#include <chrono>
#include <ctime>

#define WAIT(wait_time, callback) wait_for_bool((wait_time), (callback))
#define ASYNC(wait_time, strand, callback) \
  wait_for_bool((wait_time), (strand), (callback))

using namespace dsa;

const int SLEEP_INTERVAL = 25;
using high_resolution_clock = std::chrono::high_resolution_clock;
using time_point = std::chrono::high_resolution_clock::time_point;

class MockNode : public NodeModel {
 public:
  std::unique_ptr<SubscribeOptions> first_subscribe_options;
  std::unique_ptr<SubscribeOptions> second_subscribe_options;

  explicit MockNode(LinkStrandRef strand) : NodeModel(std::move(strand)){};

  void on_subscribe(const SubscribeOptions &options) override {
    first_subscribe_options.reset(new SubscribeOptions(options));
    if (_subscribe_callback != nullptr) {
      set_value(Variant("hello"));
    }
  }
};

int main() {
  App app;

  TestConfig server_config(app);

  MockNode *root_node = new MockNode(server_config.strand);

  server_config.get_link_config()->set_stream_acceptor(
      make_unique_<NodeStateManager>(ref_<MockNode>(root_node)));

  WrapperConfig client_config = server_config.get_client_config(app);

  app.async_start(2);

  //  auto tcp_server(new TcpServer(server_config));
  auto tcp_server = make_shared_<TcpServer>(server_config);
  tcp_server->start();

  auto tcp_client = make_shared_<TcpClient>(client_config);
  tcp_client->connect();

  ASYNC(500, (*client_config.strand)(),
        [&]() { return tcp_client->get_session().is_connected(); });

  SubscribeOptions initial_options;
  initial_options.queue_time = 0x1234;
  initial_options.queue_size = 0x5678;

  ref_<const SubscribeResponseMessage> last_response;

  const uint16_t MAX_NUM_MSGS = 0xffff;
  uint16_t idx = 0;
  time_point start_time_point, end_time_point;

  start_time_point = high_resolution_clock::now();
  while (idx < MAX_NUM_MSGS) {
    auto subscribe_stream = tcp_client->get_session().requester.subscribe(
        "",
        [&](ref_<const SubscribeResponseMessage> &&msg,
            IncomingSubscribeStream &stream) {
          if (idx == (MAX_NUM_MSGS - 1)) {
            last_response = std::move(msg);
          }
        },
        initial_options);

    // move out of the loop?
    if (idx == (MAX_NUM_MSGS - 1)) {
      int waited = 0;
      while (waited < MAX_NUM_MSGS * 100) {
        if (last_response != nullptr) {
          end_time_point = high_resolution_clock::now();
          break;
        }

        boost::this_thread::sleep(
            boost::posix_time::milliseconds(SLEEP_INTERVAL));
        waited += SLEEP_INTERVAL;
      }
    }

    idx++;
  }

  std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                    end_time_point - start_time_point)
                   .count()
            << std::endl;

  Server::close_in_strand(tcp_server);
  Client::close_in_strand(tcp_client);

  app.close();

  WAIT(500, [&]() { return app.is_stopped(); });

  if (!app.is_stopped()) {
    app.force_stop();
  }

  app.wait();
}
<|endoftext|>


<commit_before>/*
 * 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/.
 *
 * Copyright (C) 2017, James R. Barlow (https://github.com/jbarlow83/)
 */

#include <sstream>
#include <iostream>
#include <iomanip>
#include <cctype>

#include "pikepdf.h"
#include "parsers.h"

#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Buffer.hh>

py::size_t page_index(QPDF &owner, QPDFObjectHandle page)
{
    if (&owner != page.getOwningQPDF())
        throw py::value_error("Page is not in this Pdf");

    int idx;
    try {
        idx = owner.findPage(page);
    } catch (const QPDFExc &e) {
        if (std::string(e.what()).find("page object not referenced") >= 0)
            throw py::value_error("Page is not consistently registered with Pdf");
        throw e;
    }
    if (idx < 0) {
        // LCOV_EXCL_START
        throw std::logic_error("Page index is negative");
        // LCOV_EXCL_STOP
    }

    return idx;
}

std::string label_string_from_dict(QPDFObjectHandle label_dict)
{
    auto impl =
        py::module_::import("pikepdf._cpphelpers").attr("label_from_label_dict");
    py::str result = impl(label_dict);
    return result;
}

void init_page(py::module_ &m)
{
    py::class_<QPDFPageObjectHelper,
        std::shared_ptr<QPDFPageObjectHelper>,
        QPDFObjectHelper>(m, "Page")
        .def(py::init<QPDFObjectHandle &>())
        .def(py::init([](QPDFPageObjectHelper &poh) {
            return QPDFPageObjectHelper(poh.getObjectHandle());
        }))
        .def(
            "__copy__", [](QPDFPageObjectHelper &poh) { return poh.shallowCopyPage(); })
        .def_property_readonly("_images", &QPDFPageObjectHelper::getImages)
        .def("_get_mediabox", &QPDFPageObjectHelper::getMediaBox)
        .def("_get_cropbox", &QPDFPageObjectHelper::getCropBox)
        .def("_get_trimbox", &QPDFPageObjectHelper::getTrimBox)
        .def(
            "externalize_inline_images",
            [](QPDFPageObjectHelper &poh, size_t min_size = 0, bool shallow = false) {
                return poh.externalizeInlineImages(min_size, shallow);
            },
            py::arg("min_size") = 0,
            py::arg("shallow")  = false,
            R"~~~(
                Convert inlines image to normal (external) images.

                Args:
                    min_size (int): minimum size in bytes
                    shallow (bool): If False, recurse into nested Form XObjects.
                        If True, do not recurse.
            )~~~")
        .def("rotate",
            &QPDFPageObjectHelper::rotatePage,
            py::arg("angle"),
            py::arg("relative"),
            R"~~~(
                Rotate a page.

                If ``relative`` is ``False``, set the rotation of the
                page to angle. Otherwise, add angle to the rotation of the
                page. ``angle`` must be a multiple of ``90``. Adding ``90`` to
                the rotation rotates clockwise by ``90`` degrees.
            )~~~")
        .def("contents_coalesce",
            &QPDFPageObjectHelper::coalesceContentStreams,
            R"~~~(
                Coalesce a page's content streams.

                A page's content may be a
                stream or an array of streams. If this page's content is an
                array, concatenate the streams into a single stream. This can
                be useful when working with files that split content streams in
                arbitrary spots, such as in the middle of a token, as that can
                confuse some software.
            )~~~")
        .def(
            "_contents_add",
            [](QPDFPageObjectHelper &poh, QPDFObjectHandle &contents, bool prepend) {
                return poh.addPageContents(contents, prepend);
            },
            py::arg("contents"),
            py::kw_only(),
            py::arg("prepend") = false)
        .def(
            "_contents_add",
            [](QPDFPageObjectHelper &poh, py::bytes contents, bool prepend) {
                auto q = poh.getObjectHandle().getOwningQPDF();
                if (!q) {
                    // LCOV_EXCL_START
                    throw std::logic_error("QPDFPageObjectHelper not attached to QPDF");
                    // LCOV_EXCL_STOP
                }
                auto stream = QPDFObjectHandle::newStream(q, contents);
                return poh.addPageContents(stream, prepend);
            },
            py::arg("contents"),
            py::kw_only(),
            py::arg("prepend") = false)
        .def("remove_unreferenced_resources",
            &QPDFPageObjectHelper::removeUnreferencedResources,
            R"~~~(
                Removes from the resources dictionary any object not referenced in the content stream.

                A page's resources dictionary maps names to objects elsewhere
                in the file. This method walks through a page's contents and
                keeps tracks of which resources are referenced somewhere in the
                contents. Then it removes from the resources dictionary any
                object that is not referenced in the contents. This
                method is used by page splitting code to avoid copying unused
                objects in files that used shared resource dictionaries across
                multiple pages.
            )~~~")
        .def("as_form_xobject",
            &QPDFPageObjectHelper::getFormXObjectForPage,
            py::arg("handle_transformations") = true,
            R"~~~(
                Return a form XObject that draws this page.

                This is useful for
                n-up operations, underlay, overlay, thumbnail generation, or
                any other case in which it is useful to replicate the contents
                of a page in some other context. The dictionaries are shallow
                copies of the original page dictionary, and the contents are
                coalesced from the page's contents. The resulting object handle
                is not referenced anywhere.

                Args:
                    handle_transformations (bool): If True, the resulting form
                        XObject's ``/Matrix`` will be set to replicate rotation
                        (``/Rotate``) and scaling (``/UserUnit``) in the page's
                        dictionary. In this way, the page's transformations will
                        be preserved when placing this object on another page.
            )~~~")
        .def(
            "calc_form_xobject_placement",
            [](QPDFPageObjectHelper &poh,
                QPDFObjectHandle formx,
                QPDFObjectHandle name,
                QPDFObjectHandle::Rectangle rect,
                bool invert_transformations,
                bool allow_shrink,
                bool allow_expand) -> py::bytes {
                return py::bytes(poh.placeFormXObject(formx,
                    name.getName(),
                    rect,
                    invert_transformations,
                    allow_shrink,
                    allow_expand));
            },
            py::arg("formx"),
            py::arg("name"),
            py::arg("rect"),
            py::kw_only(),
            py::arg("invert_transformations") = true,
            py::arg("allow_shrink")           = true,
            py::arg("allow_expand")           = false,
            R"~~~(
                Generate content stream segment to place a Form XObject on this page.

                The content stream segment must be then be added to the page's
                content stream.

                The default keyword parameters will preserve the aspect ratio.

                Args:
                    formx: The Form XObject to place.
                    name: The name of the Form XObject in this page's /Resources
                        dictionary.
                    rect: Rectangle describing the desired placement of the Form
                        XObject.
                    invert_transformations: Apply /Rotate and /UserUnit scaling
                        when determining FormX Object placement.
                    allow_shrink: Allow the Form XObject to take less than the
                        full dimensions of rect.
                    allow_expand: Expand the Form XObject to occupy all of rect.

                .. versionadded:: 2.14
            )~~~")
        .def(
            "get_filtered_contents",
            [](QPDFPageObjectHelper &poh,
                QPDFObjectHandle::TokenFilter &tf) -> py::bytes {
                Pl_Buffer pl_buffer("filter_page");
                poh.filterContents(&tf, &pl_buffer);

                PointerHolder<Buffer> buf(pl_buffer.getBuffer());
                auto data = reinterpret_cast<const char *>(buf->getBuffer());
                auto size = buf->getSize();
                return py::bytes(data, size);
            },
            py::arg("tf"),
            R"~~~(
                Apply a :class:`pikepdf.TokenFilter` to a content stream, without modifying it.

                This may be used when the results of a token filter do not need
                to be applied, such as when filtering is being used to retrieve
                information rather than edit the content stream.

                Note that it is possible to create a subclassed ``TokenFilter``
                that saves information of interest to its object attributes; it
                is not necessary to return data in the content stream.

                To modify the content stream, use :meth:`pikepdf.Page.add_content_token_filter`.

                Returns:
                    The modified content stream.
            )~~~")
        .def(
            "add_content_token_filter",
            [](QPDFPageObjectHelper &poh,
                PointerHolder<QPDFObjectHandle::TokenFilter> tf) {
                // TokenFilters may be processed after the Python objects have gone
                // out of scope, so we need to keep them alive by attaching them to
                // the corresponding QPDF object.
                auto pyqpdf = py::cast(poh.getObjectHandle().getOwningQPDF());
                auto pytf   = py::cast(tf);
                py::detail::keep_alive_impl(pyqpdf, pytf);

                poh.addContentTokenFilter(tf);
            },
            py::keep_alive<1, 2>(),
            py::arg("tf"),
            R"~~~(
                Attach a :class:`pikepdf.TokenFilter` to a page's content stream.

                This function applies token filters lazily, if/when the page's
                content stream is read for any reason, such as when the PDF is
                saved. If never access, the token filter is not applied.

                Multiple token filters may be added to a page/content stream.

                Token filters may not be removed after being attached to a Pdf.
                Close and reopen the Pdf to remove token filters.

                If the page's contents is an array of streams, it is coalesced.
            )~~~")
        .def(
            "parse_contents",
            [](QPDFPageObjectHelper &poh, PyParserCallbacks &parsercallbacks) {
                poh.parseContents(&parsercallbacks);
            },
            R"~~~(
                Parse a page's content streams using a :class:`pikepdf.StreamParser`.

                The content stream may be interpreted by the StreamParser but is
                not altered.

                If the page's contents is an array of streams, it is coalesced.
            )~~~")
        .def_property_readonly(
            "index",
            [](QPDFPageObjectHelper &poh) {
                auto this_page = poh.getObjectHandle();
                auto p_owner   = this_page.getOwningQPDF();
                if (!p_owner)
                    throw py::value_error("Page is not attached to a Pdf");
                auto &owner = *p_owner;
                return page_index(owner, this_page);
            },
            R"~~~(
                Returns the zero-based index of this page in the pages list.

                That is, returns ``n`` such that ``pdf.pages[n] == this_page``.
                A ``ValueError`` exception is thrown if the page is not attached
                to this ``Pdf``.

                .. versionadded:: 2.2
            )~~~")
        .def_property_readonly(
            "label",
            [](QPDFPageObjectHelper &poh) {
                auto this_page = poh.getObjectHandle();
                auto p_owner   = this_page.getOwningQPDF();
                if (!p_owner)
                    throw py::value_error("Page is not attached to a Pdf");
                auto &owner = *p_owner;
                auto index  = page_index(owner, this_page);

                QPDFPageLabelDocumentHelper pldh(owner);
                auto label_dict = pldh.getLabelForPage(index);
                if (label_dict.isNull())
                    return std::to_string(index + 1);

                return label_string_from_dict(label_dict);
            },
            R"~~~(
                Returns the page label for this page, accounting for section numbers.

                For example, if the PDF defines a preface with lower case Roman
                numerals (i, ii, iii...), followed by standard numbers, followed
                by an appendix (A-1, A-2, ...), this function returns the appropriate
                label as a string.

                It is possible for a PDF to define page labels such that multiple
                pages have the same labels. Labels are not guaranteed to
                be unique.

                .. versionadded:: 2.2

                .. versionchanged:: 2.9
                    Returns the ordinary page number if no special rules for page
                    numbers are defined.
            )~~~");
}
<commit_msg>add_content_token_filter keep_alive is also unnecessary<commit_after>/*
 * 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/.
 *
 * Copyright (C) 2017, James R. Barlow (https://github.com/jbarlow83/)
 */

#include <sstream>
#include <iostream>
#include <iomanip>
#include <cctype>

#include "pikepdf.h"
#include "parsers.h"

#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Buffer.hh>

py::size_t page_index(QPDF &owner, QPDFObjectHandle page)
{
    if (&owner != page.getOwningQPDF())
        throw py::value_error("Page is not in this Pdf");

    int idx;
    try {
        idx = owner.findPage(page);
    } catch (const QPDFExc &e) {
        if (std::string(e.what()).find("page object not referenced") >= 0)
            throw py::value_error("Page is not consistently registered with Pdf");
        throw e;
    }
    if (idx < 0) {
        // LCOV_EXCL_START
        throw std::logic_error("Page index is negative");
        // LCOV_EXCL_STOP
    }

    return idx;
}

std::string label_string_from_dict(QPDFObjectHandle label_dict)
{
    auto impl =
        py::module_::import("pikepdf._cpphelpers").attr("label_from_label_dict");
    py::str result = impl(label_dict);
    return result;
}

void init_page(py::module_ &m)
{
    py::class_<QPDFPageObjectHelper,
        std::shared_ptr<QPDFPageObjectHelper>,
        QPDFObjectHelper>(m, "Page")
        .def(py::init<QPDFObjectHandle &>())
        .def(py::init([](QPDFPageObjectHelper &poh) {
            return QPDFPageObjectHelper(poh.getObjectHandle());
        }))
        .def(
            "__copy__", [](QPDFPageObjectHelper &poh) { return poh.shallowCopyPage(); })
        .def_property_readonly("_images", &QPDFPageObjectHelper::getImages)
        .def("_get_mediabox", &QPDFPageObjectHelper::getMediaBox)
        .def("_get_cropbox", &QPDFPageObjectHelper::getCropBox)
        .def("_get_trimbox", &QPDFPageObjectHelper::getTrimBox)
        .def(
            "externalize_inline_images",
            [](QPDFPageObjectHelper &poh, size_t min_size = 0, bool shallow = false) {
                return poh.externalizeInlineImages(min_size, shallow);
            },
            py::arg("min_size") = 0,
            py::arg("shallow")  = false,
            R"~~~(
                Convert inlines image to normal (external) images.

                Args:
                    min_size (int): minimum size in bytes
                    shallow (bool): If False, recurse into nested Form XObjects.
                        If True, do not recurse.
            )~~~")
        .def("rotate",
            &QPDFPageObjectHelper::rotatePage,
            py::arg("angle"),
            py::arg("relative"),
            R"~~~(
                Rotate a page.

                If ``relative`` is ``False``, set the rotation of the
                page to angle. Otherwise, add angle to the rotation of the
                page. ``angle`` must be a multiple of ``90``. Adding ``90`` to
                the rotation rotates clockwise by ``90`` degrees.
            )~~~")
        .def("contents_coalesce",
            &QPDFPageObjectHelper::coalesceContentStreams,
            R"~~~(
                Coalesce a page's content streams.

                A page's content may be a
                stream or an array of streams. If this page's content is an
                array, concatenate the streams into a single stream. This can
                be useful when working with files that split content streams in
                arbitrary spots, such as in the middle of a token, as that can
                confuse some software.
            )~~~")
        .def(
            "_contents_add",
            [](QPDFPageObjectHelper &poh, QPDFObjectHandle &contents, bool prepend) {
                return poh.addPageContents(contents, prepend);
            },
            py::arg("contents"),
            py::kw_only(),
            py::arg("prepend") = false)
        .def(
            "_contents_add",
            [](QPDFPageObjectHelper &poh, py::bytes contents, bool prepend) {
                auto q = poh.getObjectHandle().getOwningQPDF();
                if (!q) {
                    // LCOV_EXCL_START
                    throw std::logic_error("QPDFPageObjectHelper not attached to QPDF");
                    // LCOV_EXCL_STOP
                }
                auto stream = QPDFObjectHandle::newStream(q, contents);
                return poh.addPageContents(stream, prepend);
            },
            py::arg("contents"),
            py::kw_only(),
            py::arg("prepend") = false)
        .def("remove_unreferenced_resources",
            &QPDFPageObjectHelper::removeUnreferencedResources,
            R"~~~(
                Removes from the resources dictionary any object not referenced in the content stream.

                A page's resources dictionary maps names to objects elsewhere
                in the file. This method walks through a page's contents and
                keeps tracks of which resources are referenced somewhere in the
                contents. Then it removes from the resources dictionary any
                object that is not referenced in the contents. This
                method is used by page splitting code to avoid copying unused
                objects in files that used shared resource dictionaries across
                multiple pages.
            )~~~")
        .def("as_form_xobject",
            &QPDFPageObjectHelper::getFormXObjectForPage,
            py::arg("handle_transformations") = true,
            R"~~~(
                Return a form XObject that draws this page.

                This is useful for
                n-up operations, underlay, overlay, thumbnail generation, or
                any other case in which it is useful to replicate the contents
                of a page in some other context. The dictionaries are shallow
                copies of the original page dictionary, and the contents are
                coalesced from the page's contents. The resulting object handle
                is not referenced anywhere.

                Args:
                    handle_transformations (bool): If True, the resulting form
                        XObject's ``/Matrix`` will be set to replicate rotation
                        (``/Rotate``) and scaling (``/UserUnit``) in the page's
                        dictionary. In this way, the page's transformations will
                        be preserved when placing this object on another page.
            )~~~")
        .def(
            "calc_form_xobject_placement",
            [](QPDFPageObjectHelper &poh,
                QPDFObjectHandle formx,
                QPDFObjectHandle name,
                QPDFObjectHandle::Rectangle rect,
                bool invert_transformations,
                bool allow_shrink,
                bool allow_expand) -> py::bytes {
                return py::bytes(poh.placeFormXObject(formx,
                    name.getName(),
                    rect,
                    invert_transformations,
                    allow_shrink,
                    allow_expand));
            },
            py::arg("formx"),
            py::arg("name"),
            py::arg("rect"),
            py::kw_only(),
            py::arg("invert_transformations") = true,
            py::arg("allow_shrink")           = true,
            py::arg("allow_expand")           = false,
            R"~~~(
                Generate content stream segment to place a Form XObject on this page.

                The content stream segment must be then be added to the page's
                content stream.

                The default keyword parameters will preserve the aspect ratio.

                Args:
                    formx: The Form XObject to place.
                    name: The name of the Form XObject in this page's /Resources
                        dictionary.
                    rect: Rectangle describing the desired placement of the Form
                        XObject.
                    invert_transformations: Apply /Rotate and /UserUnit scaling
                        when determining FormX Object placement.
                    allow_shrink: Allow the Form XObject to take less than the
                        full dimensions of rect.
                    allow_expand: Expand the Form XObject to occupy all of rect.

                .. versionadded:: 2.14
            )~~~")
        .def(
            "get_filtered_contents",
            [](QPDFPageObjectHelper &poh,
                QPDFObjectHandle::TokenFilter &tf) -> py::bytes {
                Pl_Buffer pl_buffer("filter_page");
                poh.filterContents(&tf, &pl_buffer);

                PointerHolder<Buffer> buf(pl_buffer.getBuffer());
                auto data = reinterpret_cast<const char *>(buf->getBuffer());
                auto size = buf->getSize();
                return py::bytes(data, size);
            },
            py::arg("tf"),
            R"~~~(
                Apply a :class:`pikepdf.TokenFilter` to a content stream, without modifying it.

                This may be used when the results of a token filter do not need
                to be applied, such as when filtering is being used to retrieve
                information rather than edit the content stream.

                Note that it is possible to create a subclassed ``TokenFilter``
                that saves information of interest to its object attributes; it
                is not necessary to return data in the content stream.

                To modify the content stream, use :meth:`pikepdf.Page.add_content_token_filter`.

                Returns:
                    The modified content stream.
            )~~~")
        .def(
            "add_content_token_filter",
            [](QPDFPageObjectHelper &poh,
                PointerHolder<QPDFObjectHandle::TokenFilter> tf) {
                // TokenFilters may be processed after the Python objects have gone
                // out of scope, so we need to keep them alive by attaching them to
                // the corresponding QPDF object.
                auto pyqpdf = py::cast(poh.getObjectHandle().getOwningQPDF());
                auto pytf   = py::cast(tf);
                py::detail::keep_alive_impl(pyqpdf, pytf);

                poh.addContentTokenFilter(tf);
            },
            py::arg("tf"),
            R"~~~(
                Attach a :class:`pikepdf.TokenFilter` to a page's content stream.

                This function applies token filters lazily, if/when the page's
                content stream is read for any reason, such as when the PDF is
                saved. If never access, the token filter is not applied.

                Multiple token filters may be added to a page/content stream.

                Token filters may not be removed after being attached to a Pdf.
                Close and reopen the Pdf to remove token filters.

                If the page's contents is an array of streams, it is coalesced.
            )~~~")
        .def(
            "parse_contents",
            [](QPDFPageObjectHelper &poh, PyParserCallbacks &parsercallbacks) {
                poh.parseContents(&parsercallbacks);
            },
            R"~~~(
                Parse a page's content streams using a :class:`pikepdf.StreamParser`.

                The content stream may be interpreted by the StreamParser but is
                not altered.

                If the page's contents is an array of streams, it is coalesced.
            )~~~")
        .def_property_readonly(
            "index",
            [](QPDFPageObjectHelper &poh) {
                auto this_page = poh.getObjectHandle();
                auto p_owner   = this_page.getOwningQPDF();
                if (!p_owner)
                    throw py::value_error("Page is not attached to a Pdf");
                auto &owner = *p_owner;
                return page_index(owner, this_page);
            },
            R"~~~(
                Returns the zero-based index of this page in the pages list.

                That is, returns ``n`` such that ``pdf.pages[n] == this_page``.
                A ``ValueError`` exception is thrown if the page is not attached
                to this ``Pdf``.

                .. versionadded:: 2.2
            )~~~")
        .def_property_readonly(
            "label",
            [](QPDFPageObjectHelper &poh) {
                auto this_page = poh.getObjectHandle();
                auto p_owner   = this_page.getOwningQPDF();
                if (!p_owner)
                    throw py::value_error("Page is not attached to a Pdf");
                auto &owner = *p_owner;
                auto index  = page_index(owner, this_page);

                QPDFPageLabelDocumentHelper pldh(owner);
                auto label_dict = pldh.getLabelForPage(index);
                if (label_dict.isNull())
                    return std::to_string(index + 1);

                return label_string_from_dict(label_dict);
            },
            R"~~~(
                Returns the page label for this page, accounting for section numbers.

                For example, if the PDF defines a preface with lower case Roman
                numerals (i, ii, iii...), followed by standard numbers, followed
                by an appendix (A-1, A-2, ...), this function returns the appropriate
                label as a string.

                It is possible for a PDF to define page labels such that multiple
                pages have the same labels. Labels are not guaranteed to
                be unique.

                .. versionadded:: 2.2

                .. versionchanged:: 2.9
                    Returns the ordinary page number if no special rules for page
                    numbers are defined.
            )~~~");
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_CONTRIB_RAW_STRING_HPP
#define TAOCPP_PEGTL_INCLUDE_CONTRIB_RAW_STRING_HPP

#include "../apply_mode.hpp"
#include "../config.hpp"
#include "../nothing.hpp"
#include "../rewind_mode.hpp"

#include "../internal/must.hpp"
#include "../internal/skip_control.hpp"
#include "../internal/until.hpp"

#include "../analysis/generic.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         struct raw_string_state
         {
            template< typename Input, typename... States >
            raw_string_state( const Input&, States&&... )
            {
            }

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename... States >
            void success( Input& in, States&&... ) const
            {
               in.bump_in_this_line( marker_size );
            }

            raw_string_state( const raw_string_state& ) = delete;
            void operator=( const raw_string_state& ) = delete;

            std::size_t marker_size = 0;
         };

         template< char Open, char Marker >
         struct raw_string_open
         {
            using analyze_t = analysis::generic< analysis::rule_type::ANY >;

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename State >
            static bool match( Input& in, State& ls )
            {
               if( in.empty() || ( in.peek_char( 0 ) != Open ) ) {
                  return false;
               }
               for( std::size_t i = 1; i < in.size( i + 1 ); ++i ) {
                  switch( const auto c = in.peek_char( i ) ) {
                     case Open:
                        ls.marker_size = i + 1;
                        in.bump( ls.marker_size );
                        eol::match( in );
                        return true;
                     case Marker:
                        break;
                     default:
                        return false;
                  }
               }
               return false;
            }
         };

         template< char Open, char Marker >
         struct skip_control< raw_string_open< Open, Marker > > : std::true_type
         {
         };

         template< char Marker, char Close >
         struct at_raw_string_close
         {
            using analyze_t = analysis::generic< analysis::rule_type::ANY >;

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename State >
            static bool match( Input& in, const State& ls )
            {
               if( in.size( ls.marker_size ) < ls.marker_size ) {
                  return false;
               }
               if( in.peek_char( 0 ) != Close ) {
                  return false;
               }
               if( in.peek_char( ls.marker_size - 1 ) != Close ) {
                  return false;
               }
               for( std::size_t i = 0; i < ls.marker_size - 2; ++i ) {
                  if( in.peek_char( i + 1 ) != Marker ) {
                     return false;
                  }
               }
               return true;
            }
         };

         template< char Marker, char Close >
         struct skip_control< at_raw_string_close< Marker, Close > > : std::true_type
         {
         };

      }  // namespace internal

      // raw_string matches Lua-style long literals.
      //
      // The following description was taken from the Lua documentation
      // (see http://www.lua.org/docs.html):
      //
      // - An "opening long bracket of level n" is defined as an opening square
      //   bracket followed by n equal signs followed by another opening square
      //   bracket. So, an opening long bracket of level 0 is written as `[[`,
      //   an opening long bracket of level 1 is written as `[=[`, and so on.
      // - A "closing long bracket" is defined similarly; for instance, a closing
      //   long bracket of level 4 is written as `]====]`.
      // - A "long literal" starts with an opening long bracket of any level and
      //   ends at the first closing long bracket of the same level. It can
      //   contain any text except a closing bracket of the same level.
      // - Literals in this bracketed form can run for several lines, do not
      //   interpret any escape sequences, and ignore long brackets of any other
      //   level.
      // - For convenience, when the opening long bracket is immediately followed
      //   by a newline, the newline is not included in the string.
      //
      // Note that unlike Lua's long literal, a raw_string is customizable to use
      // other characters than `[`, `=` and `]` for matching. Also note that Lua
      // introduced newline-specific replacements in Lua 5.2, which we do not
      // support on the grammar level.

      template< char Open, char Marker, char Close, typename... Contents >
      struct raw_string
      {
         // This is used internally.
         using open = internal::raw_string_open< Open, Marker >;

         // This is used for binding the apply()-method and for error-reporting when a raw string is not closed properly.
         struct content : internal::until< internal::at_raw_string_close< Marker, Close >, Contents... >
         {
         };

         using analyze_t = analysis::generic< analysis::rule_type::SEQ, open, internal::must< content > >;

         template< apply_mode A,
                   rewind_mode M,
                   template< typename... > class Action,
                   template< typename... > class Control,
                   typename Input,
                   typename... States >
         static bool match( Input& in, States&&... st )
         {
            internal::raw_string_state s( const_cast< const Input& >( in ), st... );

            if( Control< internal::seq< open, internal::must< content > > >::template match< A, M, Action, Control >( in, s ) ) {
               s.template success< A, M, Action, Control >( in, st... );
               return true;
            }
            return false;
         }
      };

   }  // namespace TAOCPP_PEGTL_NAMESPACE

}  // namespace tao

#endif
<commit_msg>Fix includes<commit_after>// Copyright (c) 2014-2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_CONTRIB_RAW_STRING_HPP
#define TAOCPP_PEGTL_INCLUDE_CONTRIB_RAW_STRING_HPP

#include "../apply_mode.hpp"
#include "../config.hpp"
#include "../rewind_mode.hpp"

#include "../internal/must.hpp"
#include "../internal/seq.hpp"
#include "../internal/skip_control.hpp"
#include "../internal/until.hpp"

#include "../analysis/generic.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         struct raw_string_state
         {
            template< typename Input, typename... States >
            raw_string_state( const Input&, States&&... )
            {
            }

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename... States >
            void success( Input& in, States&&... ) const
            {
               in.bump_in_this_line( marker_size );
            }

            raw_string_state( const raw_string_state& ) = delete;
            void operator=( const raw_string_state& ) = delete;

            std::size_t marker_size = 0;
         };

         template< char Open, char Marker >
         struct raw_string_open
         {
            using analyze_t = analysis::generic< analysis::rule_type::ANY >;

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename State >
            static bool match( Input& in, State& ls )
            {
               if( in.empty() || ( in.peek_char( 0 ) != Open ) ) {
                  return false;
               }
               for( std::size_t i = 1; i < in.size( i + 1 ); ++i ) {
                  switch( const auto c = in.peek_char( i ) ) {
                     case Open:
                        ls.marker_size = i + 1;
                        in.bump( ls.marker_size );
                        eol::match( in );
                        return true;
                     case Marker:
                        break;
                     default:
                        return false;
                  }
               }
               return false;
            }
         };

         template< char Open, char Marker >
         struct skip_control< raw_string_open< Open, Marker > > : std::true_type
         {
         };

         template< char Marker, char Close >
         struct at_raw_string_close
         {
            using analyze_t = analysis::generic< analysis::rule_type::ANY >;

            template< apply_mode A,
                      rewind_mode,
                      template< typename... > class Action,
                      template< typename... > class Control,
                      typename Input,
                      typename State >
            static bool match( Input& in, const State& ls )
            {
               if( in.size( ls.marker_size ) < ls.marker_size ) {
                  return false;
               }
               if( in.peek_char( 0 ) != Close ) {
                  return false;
               }
               if( in.peek_char( ls.marker_size - 1 ) != Close ) {
                  return false;
               }
               for( std::size_t i = 0; i < ls.marker_size - 2; ++i ) {
                  if( in.peek_char( i + 1 ) != Marker ) {
                     return false;
                  }
               }
               return true;
            }
         };

         template< char Marker, char Close >
         struct skip_control< at_raw_string_close< Marker, Close > > : std::true_type
         {
         };

      }  // namespace internal

      // raw_string matches Lua-style long literals.
      //
      // The following description was taken from the Lua documentation
      // (see http://www.lua.org/docs.html):
      //
      // - An "opening long bracket of level n" is defined as an opening square
      //   bracket followed by n equal signs followed by another opening square
      //   bracket. So, an opening long bracket of level 0 is written as `[[`,
      //   an opening long bracket of level 1 is written as `[=[`, and so on.
      // - A "closing long bracket" is defined similarly; for instance, a closing
      //   long bracket of level 4 is written as `]====]`.
      // - A "long literal" starts with an opening long bracket of any level and
      //   ends at the first closing long bracket of the same level. It can
      //   contain any text except a closing bracket of the same level.
      // - Literals in this bracketed form can run for several lines, do not
      //   interpret any escape sequences, and ignore long brackets of any other
      //   level.
      // - For convenience, when the opening long bracket is immediately followed
      //   by a newline, the newline is not included in the string.
      //
      // Note that unlike Lua's long literal, a raw_string is customizable to use
      // other characters than `[`, `=` and `]` for matching. Also note that Lua
      // introduced newline-specific replacements in Lua 5.2, which we do not
      // support on the grammar level.

      template< char Open, char Marker, char Close, typename... Contents >
      struct raw_string
      {
         // This is used internally.
         using open = internal::raw_string_open< Open, Marker >;

         // This is used for binding the apply()-method and for error-reporting when a raw string is not closed properly.
         struct content : internal::until< internal::at_raw_string_close< Marker, Close >, Contents... >
         {
         };

         using analyze_t = analysis::generic< analysis::rule_type::SEQ, open, internal::must< content > >;

         template< apply_mode A,
                   rewind_mode M,
                   template< typename... > class Action,
                   template< typename... > class Control,
                   typename Input,
                   typename... States >
         static bool match( Input& in, States&&... st )
         {
            internal::raw_string_state s( const_cast< const Input& >( in ), st... );

            if( Control< internal::seq< open, internal::must< content > > >::template match< A, M, Action, Control >( in, s ) ) {
               s.template success< A, M, Action, Control >( in, st... );
               return true;
            }
            return false;
         }
      };

   }  // namespace TAOCPP_PEGTL_NAMESPACE

}  // namespace tao

#endif
<|endoftext|>


<commit_before>#include "HttpSrv.h"
#include "../../common/string_utils.h"

HttpSrv::ResponseInfo::ResponseInfo(const std::string &_content_type,
					const std::string &_server_name):
		content_type(_content_type),
		server_name(_server_name)
{
}

HttpSrv::Request::Request(const std::string &_url)
{
	parseGET(_url, values_GET);
}

HttpSrv::Connection::Connection(int sock, ResponseInfoPtr resp_info):
		m_sock(sock),
		alive(true),
		closing(false),
		m_resp_info(resp_info)
{
}

HttpSrv::Connection::~Connection()
{
	//std::cout << "http connection closed\n";
}

bool HttpSrv::Connection::recv()
{
	char bf[100];
	int nread = ::recv(m_sock, bf, 100, MSG_DONTWAIT);
	if (nread>0) {
		readbf.append(bf);
		return true;
	} else if (nread == 0) {
		alive  = false;
	}
	return false;
}

void HttpSrv::Connection::sendResponse(const std::string &_content)
{
	//Sat, 28 Dec 2013 18:33:30 GMT
	char content_len_c[50];
	sprintf(content_len_c, "%d", _content.size());
	std::string content_len(content_len_c);

	char time_c[50];
	sprintf(time_c, "%d", time(0));

	std::string response = "HTTP/1.1 200 OK\r\n"
						"Content-Type: "+m_resp_info->content_type+"\r\n"
						"Date: "+time_c+"\r\n"
						"Server: "+m_resp_info->server_name+"\r\n"
						"Connection: keep-alive\r\n"
						"Transfer-Encoding: none\r\n"
						"Content-Length: "+content_len+"\n\n"+_content+"\r\n";
	std::cout << "SENDING \n";
	sleep(4);
	size_t nsent = ::send(m_sock, response.c_str(), response.size(), MSG_DONTWAIT);
	if (nsent<=0)
		std::cout << "HttpSrv::Connection::sendResponse SEND ERROR!!_____________"
				<< nsent << std::endl;
}

/*
void HttpSrv::Connection::send(const std::string &_mess)
{
	size_t nsent = ::send(m_sock, _mess.c_str(), _mess.size(), MSG_DONTWAIT);
	if (nsent<=0)
		std::cout << "SEND ERROR!!_____________";
}*/

void HttpSrv::Connection::close()
{
	closing = true;
}

void HttpSrv::Connection::parseRequests()
{
	std::vector<std::string> lines;
	if (readbf.size()==0)
		return;
	int nextline_pos = readbf.find('\n');
	while (nextline_pos!=-1) {
		if (nextline_pos>1)
			lines.push_back(readbf.substr(0, nextline_pos));
		readbf = readbf.substr(nextline_pos+1, readbf.size()-nextline_pos-1);
		nextline_pos = readbf.find('\n');
	}
	if (lines.size()==0)
		return;

	for (int i = 0; i<lines.size(); i++)
		if (lines[i].substr(0,3)=="GET")
			requests.push(RequestPtr(new Request(lines[i])));

	lines.clear();
}

HttpSrv::RequestPtr HttpSrv::Connection::getNextRequest()
{
	RequestPtr req;
	recv();
	parseRequests();

	if (requests.size()==0)
		return req;
	req = requests.front();
	requests.pop();
	return req;
}

HttpSrv::HttpSrv(TaskLauncherPtr launcher,
			const HttpSrv::ResponseInfo &resp_info,
			boost::function<void(HttpSrv::ConnectionPtr,
								HttpSrv::RequestPtr)> request_hdl):
		m_launcher(launcher),
		m_resp_info(new ResponseInfo(resp_info)),
		m_request_hdl(request_hdl)
{
	m_poolserver.reset(new hPoolServer(launcher,
					boost::bind(&HttpSrv::handler, this, _1)));
}

HttpSrv::ConnectionPtr HttpSrv::getHttpConn(int socket)
{
	ConnectionPtr http_conn;
	std::tr1::unordered_map<int, ConnectionPtr>::iterator it =
							connections.find(socket);
	if (it==connections.end()) {
		http_conn.reset(new Connection(socket, m_resp_info));
		connections.insert(std::pair<int,ConnectionPtr>(socket, http_conn));
		return http_conn;
	} else
		return it->second;
}

void HttpSrv::closeHttpConn(int socket)
{
	ConnectionPtr http_conn;
	std::tr1::unordered_map<int, ConnectionPtr>::iterator it =
							connections.find(socket);
	if (it!=connections.end())
		connections.erase(it);
}

void HttpSrv::handler(hPoolServer::ConnectionPtr pool_conn)
{
	ConnectionPtr http_conn = getHttpConn(pool_conn->m_sock);

	RequestPtr req = http_conn->getNextRequest();

	if (!http_conn->alive) {
		closeHttpConn(pool_conn->m_sock);
		pool_conn->close();
		return;
	}

	if (req) {
		m_request_hdl(http_conn, req);
		if (!http_conn->alive || http_conn->closing) {
			closeHttpConn(pool_conn->m_sock);
			pool_conn->close();
		}
	}
}

void HttpSrv::start(int port)
{
	m_poolserver->start(port);
}
<commit_msg>remove debug code<commit_after>#include "HttpSrv.h"
#include "../../common/string_utils.h"

HttpSrv::ResponseInfo::ResponseInfo(const std::string &_content_type,
					const std::string &_server_name):
		content_type(_content_type),
		server_name(_server_name)
{
}

HttpSrv::Request::Request(const std::string &_url)
{
	parseGET(_url, values_GET);
}

HttpSrv::Connection::Connection(int sock, ResponseInfoPtr resp_info):
		m_sock(sock),
		alive(true),
		closing(false),
		m_resp_info(resp_info)
{
}

HttpSrv::Connection::~Connection()
{
	//std::cout << "http connection closed\n";
}

bool HttpSrv::Connection::recv()
{
	char bf[100];
	int nread = ::recv(m_sock, bf, 100, MSG_DONTWAIT);
	if (nread>0) {
		readbf.append(bf);
		return true;
	} else if (nread == 0) {
		alive  = false;
	}
	return false;
}

void HttpSrv::Connection::sendResponse(const std::string &_content)
{
	//Sat, 28 Dec 2013 18:33:30 GMT
	char content_len_c[50];
	sprintf(content_len_c, "%d", _content.size());
	std::string content_len(content_len_c);

	char time_c[50];
	sprintf(time_c, "%d", time(0));

	std::string response = "HTTP/1.1 200 OK\r\n"
						"Content-Type: "+m_resp_info->content_type+"\r\n"
						"Date: "+time_c+"\r\n"
						"Server: "+m_resp_info->server_name+"\r\n"
						"Connection: keep-alive\r\n"
						"Transfer-Encoding: none\r\n"
						"Content-Length: "+content_len+"\n\n"+_content+"\r\n";
	size_t nsent = ::send(m_sock, response.c_str(), response.size(), MSG_DONTWAIT);
	if (nsent<=0)
		std::cout << "HttpSrv::Connection::sendResponse SEND ERROR!!_____________"
				<< nsent << std::endl;
}

/*
void HttpSrv::Connection::send(const std::string &_mess)
{
	size_t nsent = ::send(m_sock, _mess.c_str(), _mess.size(), MSG_DONTWAIT);
	if (nsent<=0)
		std::cout << "SEND ERROR!!_____________";
}*/

void HttpSrv::Connection::close()
{
	closing = true;
}

void HttpSrv::Connection::parseRequests()
{
	std::vector<std::string> lines;
	if (readbf.size()==0)
		return;
	int nextline_pos = readbf.find('\n');
	while (nextline_pos!=-1) {
		if (nextline_pos>1)
			lines.push_back(readbf.substr(0, nextline_pos));
		readbf = readbf.substr(nextline_pos+1, readbf.size()-nextline_pos-1);
		nextline_pos = readbf.find('\n');
	}
	if (lines.size()==0)
		return;

	for (int i = 0; i<lines.size(); i++)
		if (lines[i].substr(0,3)=="GET")
			requests.push(RequestPtr(new Request(lines[i])));

	lines.clear();
}

HttpSrv::RequestPtr HttpSrv::Connection::getNextRequest()
{
	RequestPtr req;
	recv();
	parseRequests();

	if (requests.size()==0)
		return req;
	req = requests.front();
	requests.pop();
	return req;
}

HttpSrv::HttpSrv(TaskLauncherPtr launcher,
			const HttpSrv::ResponseInfo &resp_info,
			boost::function<void(HttpSrv::ConnectionPtr,
								HttpSrv::RequestPtr)> request_hdl):
		m_launcher(launcher),
		m_resp_info(new ResponseInfo(resp_info)),
		m_request_hdl(request_hdl)
{
	m_poolserver.reset(new hPoolServer(launcher,
					boost::bind(&HttpSrv::handler, this, _1)));
}

HttpSrv::ConnectionPtr HttpSrv::getHttpConn(int socket)
{
	ConnectionPtr http_conn;
	std::tr1::unordered_map<int, ConnectionPtr>::iterator it =
							connections.find(socket);
	if (it==connections.end()) {
		http_conn.reset(new Connection(socket, m_resp_info));
		connections.insert(std::pair<int,ConnectionPtr>(socket, http_conn));
		return http_conn;
	} else
		return it->second;
}

void HttpSrv::closeHttpConn(int socket)
{
	ConnectionPtr http_conn;
	std::tr1::unordered_map<int, ConnectionPtr>::iterator it =
							connections.find(socket);
	if (it!=connections.end())
		connections.erase(it);
}

void HttpSrv::handler(hPoolServer::ConnectionPtr pool_conn)
{
	ConnectionPtr http_conn = getHttpConn(pool_conn->m_sock);

	RequestPtr req = http_conn->getNextRequest();

	if (!http_conn->alive) {
		closeHttpConn(pool_conn->m_sock);
		pool_conn->close();
		return;
	}

	if (req) {
		m_request_hdl(http_conn, req);
		if (!http_conn->alive || http_conn->closing) {
			closeHttpConn(pool_conn->m_sock);
			pool_conn->close();
		}
	}
}

void HttpSrv::start(int port)
{
	m_poolserver->start(port);
}
<|endoftext|>