Skip to content

Commit

Permalink
Several changes:
Browse files Browse the repository at this point in the history
    - Shadow support in chart legend: patch from Stefan Rupert (#3502)
    - Fixed typo in WServerGLWidget
    - Suggested change in axis label rendering from Stefan Rupert (#3289)
    - Implemented dedicated-process deployment mode for wthttp
    - Made it possible to change the style of the progress bar on value change
  • Loading branch information
Koen Deforche committed Jul 29, 2014
1 parent abb5fb9 commit 87e2887
Show file tree
Hide file tree
Showing 46 changed files with 1,573 additions and 223 deletions.
3 changes: 2 additions & 1 deletion Doxyfile
Expand Up @@ -666,7 +666,8 @@ WARN_LOGFILE =
# with spaces.

INPUT = src/Wt \
doc/main
doc/main \
src/web

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
Expand Down
8 changes: 3 additions & 5 deletions INSTALL.html
Expand Up @@ -26,13 +26,11 @@ <h1>Wt Installation instructions on Unix-like systems</h1>

<p>
The built-in web server is more convenient during development and is
easier to setup.</p>
easier to setup. It also allows you to use WebSockets.</p>

<p>
The FastCGI based solution provides more flexibility for deployment of
the application. The built-in web server runs all sessions in a single
process, while the FastCGI based solution allows different deployment
schemes including dedicated processes per sessions.</p>
The FastCGI based solution can be more convenient for deployment behind another
web server.</p>

<p>
Each of these two choices correspond to a library, a
Expand Down
14 changes: 8 additions & 6 deletions doc/main
Expand Up @@ -233,8 +233,8 @@ namespace Wt {
widgets or application in the destructors of these objects.

The library offers two different mechanisms to map sessions onto
processes: <b>dedicated processes</b> (only with FastCGI
deployment) and <b>shared processes</b>. The first mechanisms forks
processes: <b>dedicated processes</b> (not with ISAPI
deployment) and <b>shared processes</b>. The first mechanism forks
a dedicated process for every distinct session. This provides the
kernel-level isolation of different sessions, which may be useful
for highly security sensitive applications. The second mechanism
Expand Down Expand Up @@ -554,14 +554,16 @@ appRoot=C:\Program Files\MyApplications\AppRoot
<dt><strong>dedicated-process</strong></dt>

<dd>Every session is mapped a dedicated process, allowing maximal
session isolation, but at an increased session cost. <br>
This is currently only supported using the FastCGI connector.</dd>
session isolation, but at an increased session cost. This is
not supported by the ISAPI connector. Note: when using the
<tt>wthttp</tt> adapter, this will create a listening socket
on the loopback interface (<tt>127.0.0.1</tt>) for every session,
with the parent process acting as a proxy.</dd>

<dt><strong>shared-process</strong></dt>

<dd>Sessions share a fixed number of processes, yielding a lower
session cost. <br>
This is the only option for the Wthttpd connector.</dd>
session cost.</dd>

<dt><strong>tracking</strong></dt>

Expand Down
9 changes: 7 additions & 2 deletions src/Wt/Chart/WAxis.C
Expand Up @@ -1177,8 +1177,13 @@ long WAxis::getDateNumber(WDateTime dt) const

double WAxis::calcAutoNumLabels(Orientation orientation, const Segment& s) const
{
return s.renderLength
/ (orientation == Vertical ? AUTO_V_LABEL_PIXELS : AUTO_H_LABEL_PIXELS);
if (orientation == Horizontal)
return s.renderLength
/ std::max((double)AUTO_H_LABEL_PIXELS,
WLength(defaultDateTimeFormat(s).value().size(),
WLength::FontEm).toPixels());
else
return s.renderLength / AUTO_V_LABEL_PIXELS;
}

void WAxis::render(WPainter& painter,
Expand Down
30 changes: 17 additions & 13 deletions src/Wt/Chart/WCartesianChart.C
Expand Up @@ -650,7 +650,6 @@ public:
if (series.marker() != NoMarker) {
chart_.drawMarker(series, marker_);
painter_.save();
painter_.setShadow(series.shadow());
needRestore_ = true;
} else
needRestore_ = false;
Expand Down Expand Up @@ -680,15 +679,15 @@ public:
WPen pen = WPen(series.markerPen());
setPenColor(pen, xIndex, yIndex, MarkerPenColorRole);

painter_.setPen(pen);

WBrush brush = WBrush(series.markerBrush());
setBrushColor(brush, xIndex, yIndex, MarkerBrushColorRole);
painter_.setBrush(brush);

setMarkerSize(painter_, xIndex, yIndex, series.markerSize());

painter_.drawPath(marker_);
painter_.setShadow(series.shadow());
painter_.fillPath(marker_, brush);
painter_.setShadow(WShadow());
painter_.strokePath(marker_, pen);

painter_.restore();
}

Expand Down Expand Up @@ -1490,35 +1489,40 @@ void WCartesianChart::renderLegendIcon(WPainter& painter,
const WPointF& pos,
const WDataSeries& series) const
{
WShadow shadow = painter.shadow();
switch (series.type()) {
case BarSeries: {
WPainterPath path;
path.moveTo(-6, 8);
path.lineTo(-6, -8);
path.lineTo(6, -8);
path.lineTo(6, 8);
painter.setPen(series.pen());
painter.setBrush(series.brush());
painter.translate(pos.x() + 7.5, pos.y());
painter.drawPath(path);
painter.setShadow(series.shadow());
painter.fillPath(path, series.brush());
painter.setShadow(shadow);
painter.strokePath(path, series.pen());
painter.translate(-(pos.x() + 7.5), -pos.y());
break;
}
case LineSeries:
case CurveSeries: {
painter.setPen(series.pen());
double offset = (series.pen().width() == 0 ? 0.5 : 0);
painter.setShadow(series.shadow());
painter.drawLine(pos.x(), pos.y() + offset, pos.x() + 16, pos.y() + offset);
painter.setShadow(shadow);
}
// no break;
case PointSeries: {
WPainterPath path;
drawMarker(series, path);
if (!path.isEmpty()) {
painter.translate(pos.x() + 8, pos.y());
painter.setPen(series.markerPen());
painter.setBrush(series.markerBrush());
painter.drawPath(path);
painter.setShadow(series.shadow());
painter.fillPath(path, series.markerBrush());
painter.setShadow(shadow);
painter.strokePath(path, series.markerPen());
painter.translate(- (pos.x() + 8), -pos.y());
}

Expand All @@ -1536,7 +1540,7 @@ void WCartesianChart::renderLegendItem(WPainter& painter,
renderLegendIcon(painter, pos, series);

painter.setPen(fontPen);
painter.drawText(pos.x() + 17, pos.y() - 10, 100, 20,
painter.drawText(pos.x() + 23, pos.y() - 9, 100, 20,
AlignLeft | AlignMiddle,
asString(model()->headerData(series.modelColumn())));
}
Expand Down
175 changes: 98 additions & 77 deletions src/Wt/Http/Client.C
Expand Up @@ -41,6 +41,13 @@ LOGGER("Http.Client");
class Client::Impl : public boost::enable_shared_from_this<Client::Impl>
{
public:
struct ChunkState {
enum State { Size, Data, Complete, Error } state;
std::string data;
std::size_t size;
int parsePos;
};

Impl(WIOService& ioService, WServer *server, const std::string& sessionId)
: ioService_(ioService),
resolver_(ioService_),
Expand Down Expand Up @@ -312,9 +319,10 @@ private:
if (boost::iequals(name, "Transfer-Encoding") &&
boost::iequals(value, "chunked")) {
chunkedResponse_ = true;
currentChunkSize_ = 0;
chunkSizeParsePos_ = 0;
chunkState_ = ChunkSize;
chunkState_.size = 0;
chunkState_.parsePos = 0;
chunkState_.state = ChunkState::Size;
chunkState_.data = std::string();
}
}
}
Expand Down Expand Up @@ -373,85 +381,100 @@ private:
void addBodyText(const std::string& text)
{
if (chunkedResponse_) {
std::string::const_iterator pos = text.begin();
while (pos != text.end()) {
switch (chunkState_) {
case ChunkSize: {
unsigned char ch = *(pos++);

switch (chunkSizeParsePos_) {
case -2:
if (ch != '\r') {
protocolError(); return;
}

chunkSizeParsePos_ = -1;

break;
case -1:
if (ch != '\n') {
protocolError(); return;
}

chunkSizeParsePos_ = 0;

break;
case 0:
if (ch >= '0' && ch <= '9') {
currentChunkSize_ <<= 4;
currentChunkSize_ |= (ch - '0');
} else if (ch >= 'a' && ch <= 'f') {
currentChunkSize_ <<= 4;
currentChunkSize_ |= (10 + ch - 'a');
} else if (ch >= 'A' && ch <= 'F') {
currentChunkSize_ <<= 4;
currentChunkSize_ |= (10 + ch - 'A');
} else if (ch == '\r') {
chunkSizeParsePos_ = 2;
} else if (ch == ';') {
chunkSizeParsePos_ = 1;
} else {
protocolError(); return;
}

break;
case 1:
/* Ignoring extensions and syntax for now */
if (ch == '\r')
chunkSizeParsePos_ = 2;

break;
case 2:
if (ch != '\n') {
protocolError(); return;
}

if (currentChunkSize_ == 0) {
complete();
return;
}

chunkState_ = ChunkData;
chunkedDecode(chunkState_, text);
if (chunkState_.state == ChunkState::Error) {
protocolError(); return;
} else if (chunkState_.state == ChunkState::Complete) {
complete(); return;
} else {
response_.addBodyText(chunkState_.data);
}
} else
response_.addBodyText(text);
}

static void chunkedDecode(ChunkState& chunkState, const std::string& text)
{
std::string::const_iterator pos = text.begin();
while (pos != text.end()) {
switch (chunkState.state) {
case ChunkState::Size: {
unsigned char ch = *(pos++);

switch (chunkState.parsePos) {
case -2:
if (ch != '\r') {
chunkState.state = ChunkState::Error; return;
}

chunkState.parsePos = -1;

break;
}
case ChunkData:
case -1:
if (ch != '\n') {
chunkState.state = ChunkState::Error; return;
}

std::size_t thisChunk
= std::min(std::size_t(text.end() - pos), currentChunkSize_);
response_.addBodyText(std::string(pos, pos + thisChunk));
currentChunkSize_ -= thisChunk;
pos += thisChunk;
chunkState.parsePos = 0;

break;
case 0:
if (ch >= '0' && ch <= '9') {
chunkState.size <<= 4;
chunkState.size |= (ch - '0');
} else if (ch >= 'a' && ch <= 'f') {
chunkState.size <<= 4;
chunkState.size |= (10 + ch - 'a');
} else if (ch >= 'A' && ch <= 'F') {
chunkState.size <<= 4;
chunkState.size |= (10 + ch - 'A');
} else if (ch == '\r') {
chunkState.parsePos = 2;
} else if (ch == ';') {
chunkState.parsePos = 1;
} else {
chunkState.state = ChunkState::Error; return;
}

if (currentChunkSize_ == 0) {
chunkSizeParsePos_ = -2;
chunkState_ = ChunkSize;
break;
case 1:
/* Ignoring extensions and syntax for now */
if (ch == '\r')
chunkState.parsePos = 2;

break;
case 2:
if (ch != '\n') {
chunkState.state = ChunkState::Error; return;
}

if (chunkState.size == 0) {
chunkState.state = ChunkState::Complete; return;
return;
}

chunkState.state = ChunkState::Data;
}

break;
}
} else
response_.addBodyText(text);
case ChunkState::Data: {
std::size_t thisChunk
= std::min(std::size_t(text.end() - pos), chunkState.size);
chunkState.data = std::string(pos, pos + thisChunk);
chunkState.size -= thisChunk;
pos += thisChunk;

if (chunkState.size == 0) {
chunkState.parsePos = -2;
chunkState.state = ChunkState::Size;
}
break;
}
default:
assert(false); // Illegal state
}
}
}

void protocolError()
Expand Down Expand Up @@ -488,9 +511,7 @@ private:
int timeout_;
std::size_t maximumResponseSize_, responseSize_;
bool chunkedResponse_;
enum ChunkState { ChunkSize, ChunkData } chunkState_;
std::size_t currentChunkSize_;
int chunkSizeParsePos_;
ChunkState chunkState_;
boost::system::error_code err_;
Message response_;
Signal<boost::system::error_code, Message> done_;
Expand Down
12 changes: 12 additions & 0 deletions src/Wt/WProgressBar
Expand Up @@ -122,6 +122,18 @@ public:
void setState(double minimum, double maximum, double value);

protected:
/*! \brief Update the progress bar itself.
*
* Will be called whenever the value changes, and changes
* the width of the progress bar accordingly.
*
* You can reimplement this method to apply certain
* style changes to the progress bar according to the
* value. Don't forget to call WProgressBar::updateBar
* if you still want the width to change.
*/
virtual void updateBar(DomElement& bar);

virtual void updateDom(DomElement& element, bool all);
virtual DomElementType domElementType() const;
virtual void propagateRenderOk(bool deep);
Expand Down

0 comments on commit 87e2887

Please sign in to comment.