From 37c329a3e35fabc88fbcad824a69f37c671d2132 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 14 Apr 2011 21:38:45 +0200 Subject: New algorithm for drawing thin lines Added a new QCosmeticStroker class for drawing thin lines. The class can handle both aliased and antialiased lines. The code replaces all the midpoint line drawing algorithms in the raster paintengine and gives correct subpixel positioning for lines. It gives around 30% to 50% speedup against the midpoint algorithm. If we missed that fast path, the speedup is around between a factor of 6 to 8 for lines and aliased paths and 100 and 400 for antialiased paths. Reviewed-by: Kim --- src/gui/painting/painting.pri | 4 +- src/gui/painting/qcosmeticstroker.cpp | 954 +++++++++++++++++++ src/gui/painting/qcosmeticstroker_p.h | 101 ++ src/gui/painting/qpaintengine_raster.cpp | 1520 ++---------------------------- src/gui/painting/qpaintengine_raster_p.h | 5 - src/gui/painting/qpaintengineex.cpp | 2 +- 6 files changed, 1137 insertions(+), 1449 deletions(-) create mode 100644 src/gui/painting/qcosmeticstroker.cpp create mode 100644 src/gui/painting/qcosmeticstroker_p.h diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 65e7af4..13a9ba1 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -6,6 +6,7 @@ HEADERS += \ painting/qcolor.h \ painting/qcolor_p.h \ painting/qcolormap.h \ + painting/qcosmeticstroker_p.h \ painting/qdrawutil.h \ painting/qemulationpaintengine_p.h \ painting/qgraphicssystem_p.h \ @@ -14,7 +15,7 @@ HEADERS += \ painting/qoutlinemapper_p.h \ painting/qpaintdevice.h \ painting/qpaintengine.h \ - painting/qpaintengine_p.h \ + painting/qpaintengine_p.h \ painting/qpaintengine_alpha_p.h \ painting/qpaintengine_preview_p.h \ painting/qpaintengineex_p.h \ @@ -53,6 +54,7 @@ SOURCES += \ painting/qbrush.cpp \ painting/qcolor.cpp \ painting/qcolor_p.cpp \ + painting/qcosmeticstroker.cpp \ painting/qcssutil.cpp \ painting/qdrawutil.cpp \ painting/qemulationpaintengine.cpp \ diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp new file mode 100644 index 0000000..498b154 --- /dev/null +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -0,0 +1,954 @@ +#include "qcosmeticstroker_p.h" +#include "private/qpainterpath_p.h" +#include +#include + +#if 0 +inline QString capString(int caps) +{ + QString str; + if (caps & QCosmeticStroker::CapBegin) { + str += "CapBegin "; + } + if (caps & QCosmeticStroker::CapEnd) { + str += "CapEnd "; + } + return str; +} +#endif + +#define toF26Dot6(x) ((int)((x)*64.)) + +static inline uint sourceOver(uint d, uint color) +{ + return color + BYTE_MUL(d, qAlpha(~color)); +} + +inline static int F16Dot16FixedDiv(int x, int y) +{ + if (qAbs(x) > 0x7fff) + return (((qlonglong)x) << 16) / y; + return (x << 16) / y; +} + +typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage); + +namespace { + +struct Dasher { + QCosmeticStroker *stroker; + int *pattern; + int offset; + int dashIndex; + int dashOn; + + Dasher(QCosmeticStroker *s, bool reverse, int start, int stop) + : stroker(s) + { + int delta = stop - start; + if (reverse) { + pattern = stroker->reversePattern; + offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32); + dashOn = 0; + } else { + pattern = stroker->pattern; + offset = stroker->patternOffset - ((start & 63) - 32); + dashOn = 1; + } + offset %= stroker->patternLength; + if (offset < 0) + offset += stroker->patternLength; + + dashIndex = 0; + while (offset>= pattern[dashIndex]) + ++dashIndex; + +// qDebug() << " dasher" << offset/64. << reverse << dashIndex; + stroker->patternOffset += delta; + stroker->patternOffset %= stroker->patternLength; + } + + bool on() const { + return (dashIndex + dashOn) & 1; + } + void adjust() { + offset += 64; + if (offset >= pattern[dashIndex]) { + ++dashIndex; + dashIndex %= stroker->patternSize; + } + offset %= stroker->patternLength; +// qDebug() << "dasher.adjust" << offset/64. << dashIndex; + } +}; + +struct NoDasher { + NoDasher(QCosmeticStroker *, bool, int, int) {} + bool on() const { return true; } + void adjust(int = 0) {} +}; + +}; + +template +static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps); +template +static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps); + +inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage) +{ + int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ; + int lasty = stroker->spans[stroker->current_span-1].y; + + if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) { + stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData); + stroker->current_span = 0; + } + + stroker->spans[stroker->current_span].x = ushort(x); + stroker->spans[stroker->current_span].len = 1; + stroker->spans[stroker->current_span].y = y; + stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8; + ++stroker->current_span; +} + +inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage) +{ + const QRect &cl = stroker->clip; + if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom()) + return; + + int offset = x + stroker->ppl*y; + uint c = BYTE_MUL(stroker->color, coverage); + stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c); +} + +inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int) +{ + const QRect &cl = stroker->clip; + if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom()) + return; + + int offset = x + stroker->ppl*y; + stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color); +} + +enum StrokeSelection { + Aliased = 0, + AntiAliased = 1, + Solid = 0, + Dashed = 2, + RegularDraw = 0, + FastDraw = 4 +}; + +static StrokeLine strokeLine(int strokeSelection) +{ + StrokeLine stroke; + + switch (strokeSelection) { + case Aliased|Solid|RegularDraw: + stroke = &::drawLine; + break; + case Aliased|Solid|FastDraw: + stroke = &::drawLine; + break; + case Aliased|Dashed|RegularDraw: + stroke = &::drawLine; + break; + case Aliased|Dashed|FastDraw: + stroke = &::drawLine; + break; + case AntiAliased|Solid|RegularDraw: + stroke = &drawLineAA; + break; + case AntiAliased|Solid|FastDraw: + stroke = &drawLineAA; + break; + case AntiAliased|Dashed|RegularDraw: + stroke = &drawLineAA; + break; + case AntiAliased|Dashed|FastDraw: + stroke = &drawLineAA; + break; + default: + Q_ASSERT(false); + stroke = 0; + } + return stroke; +} + +void QCosmeticStroker::setup() +{ + blend = state->penData.blend; + if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) { + clip &= state->clip->clipRect; + blend = state->penData.unclipped_blend; + } + + int strokeSelection = 0; + if (blend == state->penData.unclipped_blend + && state->penData.type == QSpanData::Solid + && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied + || state->penData.rasterBuffer->format == QImage::Format_RGB32) + && state->compositionMode() == QPainter::CompositionMode_SourceOver) + strokeSelection |= FastDraw; + + if (state->renderHints & QPainter::Antialiasing) + strokeSelection |= AntiAliased; + + const QVector &penPattern = state->lastPen.dashPattern(); + if (penPattern.isEmpty()) { + Q_ASSERT(!pattern && !reversePattern); + pattern = 0; + reversePattern = 0; + patternLength = 0; + patternSize = 0; + } else { + pattern = (int *)malloc(penPattern.size()*sizeof(int)); + reversePattern = (int *)malloc(penPattern.size()*sizeof(int)); + patternSize = penPattern.size(); + + patternLength = 0; + for (int i = 0; i < patternSize; ++i) { + patternLength += (int) qMax(1. , penPattern.at(i)*64.); + pattern[i] = patternLength; + } + patternLength = 0; + for (int i = 0; i < patternSize; ++i) { + patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.); + reversePattern[i] = patternLength; + } + strokeSelection |= Dashed; +// qDebug() << "setup: size=" << patternSize << "length=" << patternLength/64.; + } + + stroke = strokeLine(strokeSelection); + + qreal width = state->lastPen.widthF(); + if (width == 0) + opacity = 256; + else if (state->lastPen.isCosmetic()) + opacity = (int) 256*width; + else + opacity = (int) 256*width*state->txscale; + opacity = qBound(0, opacity, 256); + + drawCaps = state->lastPen.capStyle() != Qt::FlatCap; + + if (strokeSelection & FastDraw) { + color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0); + QRasterBuffer *buffer = state->penData.rasterBuffer; + pixels = (uint *)buffer->buffer(); + ppl = buffer->bytesPerLine()>>2; + } + + // setup FP clip bounds + xmin = clip.left() - 1; + xmax = clip.right() + 2; + ymin = clip.top() - 1; + ymax = clip.bottom() + 2; + + lastPixel.x = -1; +} + +// returns true if the whole line gets clipped away +bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2) +{ + // basic/rough clipping is done in floating point coordinates to avoid + // integer overflow problems. + if (x1 < xmin) { + if (x2 <= xmin) + goto clipped; + y1 += (y2 - y1)/(x2 - x1) * (xmin - x1); + x1 = xmin; + } else if (x1 > xmax) { + if (x2 >= xmax) + goto clipped; + y1 += (y2 - y1)/(x2 - x1) * (xmax - x1); + x1 = xmax; + } + if (x2 < xmin) { + lastPixel.x = -1; + y2 += (y2 - y1)/(x2 - x1) * (xmin - x2); + x2 = xmin; + } else if (x2 > xmax) { + lastPixel.x = -1; + y2 += (y2 - y1)/(x2 - x1) * (xmax - x2); + x2 = xmax; + } + + if (y1 < ymin) { + if (y2 <= ymin) + goto clipped; + x1 += (x2 - x1)/(y2 - y1) * (ymin - y1); + y1 = ymin; + } else if (y1 > ymax) { + if (y2 >= ymax) + goto clipped; + x1 += (x2 - x1)/(y2 - y1) * (ymax - y1); + y1 = ymax; + } + if (y2 < ymin) { + lastPixel.x = -1; + x2 += (x2 - x1)/(y2 - y1) * (ymin - y2); + y2 = ymin; + } else if (y2 > ymax) { + lastPixel.x = -1; + x2 += (x2 - x1)/(y2 - y1) * (ymax - y2); + y2 = ymax; + } + + return false; + + clipped: + lastPixel.x = -1; + return true; +} + + +void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2) +{ + QPointF start = p1 * state->matrix; + QPointF end = p2 * state->matrix; + + patternOffset = state->lastPen.dashOffset()*64; + lastPixel.x = -1; + + stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0); + + blend(current_span, spans, &state->penData); + current_span = 0; +} + +void QCosmeticStroker::drawPoints(const QPoint *points, int num) +{ + const QPoint *end = points + num; + while (points < end) { + QPointF p = QPointF(*points) * state->matrix; + drawPixel(this, qRound(p.x()), qRound(p.y()), 255); + ++points; + } + + blend(current_span, spans, &state->penData); + current_span = 0; +} + +void QCosmeticStroker::drawPoints(const QPointF *points, int num) +{ + const QPointF *end = points + num; + while (points < end) { + QPointF p = (*points) * state->matrix; + drawPixel(this, qRound(p.x()), qRound(p.y()), 255); + ++points; + } + + blend(current_span, spans, &state->penData); + current_span = 0; +} + +void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2) +{ + // this is basically the same code as used in the aliased stroke method, + // but it only determines the direction and last point of a line + // + // This is being used to have proper dropout control for closed contours + // by calculating the direction and last pixel of the last segment in the contour. + // the info is then used to perform dropout control when drawing the first line segment + // of the contour + lastPixel.x = -1; + lastPixel.y = -1; + + if (clipLine(rx1, ry1, rx2, ry2)) + return; + + int x1 = toF26Dot6(rx1); + int y1 = toF26Dot6(ry1); + int x2 = toF26Dot6(rx2); + int y2 = toF26Dot6(ry2); + + int dx = qAbs(x2 - x1); + int dy = qAbs(y2 - y1); + + if (dx < dy) { + // vertical + bool swapped = false; + if (y1 > y2) { + swapped = true; + qSwap(y1, y2); + qSwap(x1, x2); + } + int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1); + int x = x1 << 10; + + int y = (y1+32) >> 6; + int ys = (y2+32) >> 6; + + if (y != ys) { + x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6; + + if (swapped) { + lastPixel.x = x >> 16; + lastPixel.y = y; + lastDir = QCosmeticStroker::BottomToTop; + } else { + lastPixel.x = (x + (ys - y - 1)*xinc) >> 16; + lastPixel.y = ys - 1; + lastDir = QCosmeticStroker::TopToBottom; + } + lastAxisAligned = qAbs(xinc) < (1 << 14); + } + } else { + // horizontal + if (!dx) + return; + + bool swapped = false; + if (x1 > x2) { + swapped = true; + qSwap(x1, x2); + qSwap(y1, y2); + } + int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1); + int y = y1 << 10; + + int x = (x1+32) >> 6; + int xs = (x2+32) >> 6; + + if (x != xs) { + y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6; + + if (swapped) { + lastPixel.x = x; + lastPixel.y = y >> 16; + lastDir = QCosmeticStroker::RightToLeft; + } else { + lastPixel.x = xs - 1; + lastPixel.y = (y + (xs - x - 1)*yinc) >> 16; + lastDir = QCosmeticStroker::LeftToRight; + } + lastAxisAligned = qAbs(yinc) < (1 << 14); + } + } +// qDebug() << " moveTo: setting last pixel to x/y dir" << lastPixel.x << lastPixel.y << lastDir; +} + +static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, + const qreal *points, bool *closed) +{ + const QPainterPath::ElementType *start = t; + ++t; + + // find out if the subpath is closed + while (t < end) { + if (*t == QPainterPath::MoveToElement) + break; + ++t; + } + + int offset = t - start - 1; +// qDebug() << "subpath" << offset << points[0] << points[1] << points[2*offset] << points[2*offset+1]; + *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]); + + return t; +} + +void QCosmeticStroker::drawPath(const QVectorPath &path) +{ +// qDebug() << ">>>> drawpath" << path.convertToPainterPath() +// << "antialiasing:" << (bool)(state->renderHints & QPainter::Antialiasing) << " implicit close:" << path.hasImplicitClose(); + if (path.isEmpty()) + return; + + const qreal *points = path.points(); + const QPainterPath::ElementType *type = path.elements(); + + if (type) { + const QPainterPath::ElementType *end = type + path.elementCount(); + + while (type < end) { + Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement); + + QPointF p = QPointF(points[0], points[1]) * state->matrix; + QPointF movedTo = p; + patternOffset = state->lastPen.dashOffset()*64; + lastPixel.x = -1; + + bool closed; + const QPainterPath::ElementType *e = subPath(type, end, points, &closed); + if (closed) { + const qreal *p = points + 2*(e-type); + calculateLastPoint(p[-4], p[-3], p[-2], p[-1]); + } + int caps = (!closed & drawCaps) ? CapBegin : NoCaps; +// qDebug() << "closed =" << closed << capString(caps); + + points += 2; + ++type; + + while (type < e) { + QPointF p2 = QPointF(points[0], points[1]) * state->matrix; + switch (*type) { + case QPainterPath::MoveToElement: + Q_ASSERT(!"Logic error"); + break; + + case QPainterPath::LineToElement: + if (!closed && drawCaps && type == e - 1) + caps |= CapEnd; + stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps); + p = p2; + points += 2; + ++type; + break; + + case QPainterPath::CurveToElement: { + if (!closed && drawCaps && type == e - 3) + caps |= CapEnd; + QPointF p3 = QPointF(points[2], points[3]) * state->matrix; + QPointF p4 = QPointF(points[4], points[5]) * state->matrix; + renderCubic(p, p2, p3, p4, caps); + p = p4; + type += 3; + points += 6; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type"); + break; + } + caps = NoCaps; + } + } + } else { // !type, simple polygon + QPointF p = QPointF(points[0], points[1]) * state->matrix; + QPointF movedTo = p; + patternOffset = state->lastPen.dashOffset()*64; + lastPixel.x = -1; + + const qreal *end = points + 2*path.elementCount(); + // handle closed path case + bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]); + int caps = (!closed & drawCaps) ? CapBegin : NoCaps; + if (closed) + calculateLastPoint(end[-2], end[-1], points[0], points[1]); + + points += 2; + while (points < end) { + QPointF p2 = QPointF(points[0], points[1]) * state->matrix; + + if (!closed && drawCaps && points == end - 2) + caps |= CapEnd; + + stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps); + + p = p2; + points += 2; + caps = NoCaps; + } + if (path.hasImplicitClose()) + stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps); + } + + + blend(current_span, spans, &state->penData); + current_span = 0; +} + +void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps) +{ +// qDebug() << ">>>> renderCubic" << p1 << p2 << p3 << p4 << capString(caps); + const int maxSubDivisions = 6; + PointF points[3*maxSubDivisions + 4]; + + points[3].x = p1.x(); + points[3].y = p1.y(); + points[2].x = p2.x(); + points[2].y = p2.y(); + points[1].x = p3.x(); + points[1].y = p3.y(); + points[0].x = p4.x(); + points[0].y = p4.y(); + + PointF *p = points; + int level = maxSubDivisions; + + renderCubicSubdivision(p, level, caps); +} + +static void splitCubic(QCosmeticStroker::PointF *points) +{ + const qreal half = .5; + qreal a, b, c, d; + + points[6].x = points[3].x; + c = points[1].x; + d = points[2].x; + points[1].x = a = ( points[0].x + c ) * half; + points[5].x = b = ( points[3].x + d ) * half; + c = ( c + d ) * half; + points[2].x = a = ( a + c ) * half; + points[4].x = b = ( b + c ) * half; + points[3].x = ( a + b ) * half; + + points[6].y = points[3].y; + c = points[1].y; + d = points[2].y; + points[1].y = a = ( points[0].y + c ) * half; + points[5].y = b = ( points[3].y + d ) * half; + c = ( c + d ) * half; + points[2].y = a = ( a + c ) * half; + points[4].y = b = ( b + c ) * half; + points[3].y = ( a + b ) * half; +} + +void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps) +{ + if (level) { + qreal dx = points[3].x - points[0].x; + qreal dy = points[3].y - points[0].y; + qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy)); + + if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) > len || + qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) > len) { + splitCubic(points); + + --level; + renderCubicSubdivision(points + 3, level, caps & CapBegin); + renderCubicSubdivision(points, level, caps & CapEnd); + return; + } + } + + stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps); +} + +static inline int swapCaps(int caps) +{ + return ((caps & QCosmeticStroker::CapBegin) << 1) | + ((caps & QCosmeticStroker::CapEnd) >> 1); +} + +// adjust line by half a pixel +static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc) +{ + if (caps & QCosmeticStroker::CapBegin) { + x1 -= 32; + y -= yinc >> 1; + } + if (caps & QCosmeticStroker::CapEnd) { + x2 += 32; + } +} + +/* + The hard part about this is dropout control and avoiding douple drawing of points when + the drawing shifts from horizontal to vertical or back. + */ +template +static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps) +{ + if (stroker->clipLine(rx1, ry1, rx2, ry2)) + return; + + static const int half = 32; + int x1 = toF26Dot6(rx1) + half; + int y1 = toF26Dot6(ry1) + half; + int x2 = toF26Dot6(rx2) + half; + int y2 = toF26Dot6(ry2) + half; + + int dx = qAbs(x2 - x1); + int dy = qAbs(y2 - y1); + + QCosmeticStroker::Point last = stroker->lastPixel; + +// qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64. << capString(caps); + + if (dx < dy) { + // vertical + + bool swapped = false; + if (y1 > y2) { + swapped = true; + qSwap(y1, y2); + qSwap(x1, x2); + caps = swapCaps(caps); + --x1; --x2; --y1; --y2; + } + int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1); + int x = x1 << 10; + + capAdjust(caps, y1, y2, x, xinc); + + int y = (y1+32) >> 6; + int ys = (y2+32) >> 6; + + if (y != ys) { + x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6; + + // calculate first and last pixel and perform dropout control + QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom; + QCosmeticStroker::Point first; + first.x = x >> 16; + first.y = y; + last.x = (x + (ys - y - 1)*xinc) >> 16; + last.y = ys - 1; + if (swapped) { + qSwap(first, last); + dir = QCosmeticStroker::BottomToTop; + } + bool axisAligned = qAbs(xinc) < (1 << 14); + if (stroker->lastPixel.x >= 0) { + if (first.x == stroker->lastPixel.x && + first.y == stroker->lastPixel.y) { + // remove duplicated pixel + if (swapped) { + --ys; + } else { + ++y; + x += xinc; + } + } else if (stroker->lastDir != dir && + (((axisAligned && stroker->lastAxisAligned) && + stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) || + (qAbs(stroker->lastPixel.x - first.x) > 1 && + qAbs(stroker->lastPixel.y - first.y) > 1))) { + // have a missing pixel, insert it + if (swapped) { + ++ys; + } else { + --y; + x -= xinc; + } + } + } + stroker->lastDir = dir; + stroker->lastAxisAligned = axisAligned; + + Dasher dasher(stroker, swapped, y << 6, ys << 6); + + do { + if (dasher.on()) + drawPixel(stroker, x >> 16, y, 255); + dasher.adjust(); + x += xinc; + } while (++y < ys); + } + } else { + // horizontal + if (!dx) + return; + + bool swapped = false; + if (x1 > x2) { + swapped = true; + qSwap(x1, x2); + qSwap(y1, y2); + caps = swapCaps(caps); + --x1; --x2; --y1; --y2; + } + int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1); + int y = y1 << 10; + + capAdjust(caps, x1, x2, y, yinc); + + int x = (x1+32) >> 6; + int xs = (x2+32) >> 6; + + + if (x != xs) { + y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6; + + // calculate first and last pixel to perform dropout control + QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight; + QCosmeticStroker::Point first; + first.x = x; + first.y = y >> 16; + last.x = xs - 1; + last.y = (y + (xs - x - 1)*yinc) >> 16; + if (swapped) { + qSwap(first, last); + dir = QCosmeticStroker::RightToLeft; + } + bool axisAligned = qAbs(yinc) < (1 << 14); + if (stroker->lastPixel.x >= 0) { + if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) { + // remove duplicated pixel + if (swapped) { + --xs; + } else { + ++x; + y += yinc; + } + } else if (stroker->lastDir != dir && + (((axisAligned && stroker->lastAxisAligned) && + stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) || + (qAbs(stroker->lastPixel.x - first.x) > 1 && + qAbs(stroker->lastPixel.y - first.y) > 1))) { + // have a missing pixel, insert it + if (swapped) { + ++xs; + } else { + --x; + y -= yinc; + } + } + } + stroker->lastDir = dir; + stroker->lastAxisAligned = axisAligned; + + Dasher dasher(stroker, swapped, x << 6, xs << 6); + + do { + if (dasher.on()) + drawPixel(stroker, x, y >> 16, 255); + dasher.adjust(); + y += yinc; + } while (++x < xs); + } + } + stroker->lastPixel = last; +} + + +template +static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps) +{ + if (stroker->clipLine(rx1, ry1, rx2, ry2)) + return; + + int x1 = toF26Dot6(rx1); + int y1 = toF26Dot6(ry1); + int x2 = toF26Dot6(rx2); + int y2 = toF26Dot6(ry2); + + int dx = x2 - x1; + int dy = y2 - y1; + + if (qAbs(dx) < qAbs(dy)) { + // vertical + + int xinc = F16Dot16FixedDiv(dx, dy); + + bool swapped = false; + if (y1 > y2) { + qSwap(y1, y2); + qSwap(x1, x2); + swapped = true; + caps = swapCaps(caps); + } + + int x = (x1 - 32) << 10; + x -= ( ((y1 & 63) - 32) * xinc ) >> 6; + + capAdjust(caps, y1, y2, x, xinc); + + Dasher dasher(stroker, swapped, y1, y2); + + int y = y1 >> 6; + int ys = y2 >> 6; + + int alphaStart, alphaEnd; + if (y == ys) { + alphaStart = y2 - y1; + Q_ASSERT(alphaStart >= 0 && alphaStart < 64); + alphaEnd = 0; + } else { + alphaStart = 64 - (y1 & 63); + alphaEnd = (y2 & 63); + } +// qDebug() << "vertical" << x1/64. << y1/64. << x2/64. << y2/64.; +// qDebug() << " x=" << x << "dx=" << dx << "xi=" << (x>>16) << "xsi=" << ((x+(ys-y)*dx)>>16) << "y=" << y << "ys=" << ys; + + // draw first pixel + if (dasher.on()) { + uint alpha = (quint8)(x >> 8); + drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6); + drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6); + } + dasher.adjust(); + x += xinc; + ++y; + if (y < ys) { + do { + if (dasher.on()) { + uint alpha = (quint8)(x >> 8); + drawPixel(stroker, x>>16, y, (255-alpha)); + drawPixel(stroker, (x>>16) + 1, y, alpha); + } + dasher.adjust(); + x += xinc; + } while (++y < ys); + } + // draw last pixel + if (alphaEnd && dasher.on()) { + uint alpha = (quint8)(x >> 8); + drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6); + drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6); + } + } else { + // horizontal + if (!dx) + return; + + int yinc = F16Dot16FixedDiv(dy, dx); + + bool swapped = false; + if (x1 > x2) { + qSwap(x1, x2); + qSwap(y1, y2); + swapped = true; + caps = swapCaps(caps); + } + + int y = (y1 - 32) << 10; + y -= ( ((x1 & 63) - 32) * yinc ) >> 6; + + capAdjust(caps, x1, x2, y, yinc); + + Dasher dasher(stroker, swapped, x1, x2); + + int x = x1 >> 6; + int xs = x2 >> 6; + +// qDebug() << "horizontal" << x1/64. << y1/64. << x2/64. << y2/64.; +// qDebug() << " y=" << y << "dy=" << dy << "x=" << x << "xs=" << xs << "yi=" << (y>>16) << "ysi=" << ((y+(xs-x)*dy)>>16); + int alphaStart, alphaEnd; + if (x == xs) { + alphaStart = x2 - x1; + Q_ASSERT(alphaStart >= 0 && alphaStart < 64); + alphaEnd = 0; + } else { + alphaStart = 64 - (x1 & 63); + alphaEnd = (x2 & 63); + } + + // draw first pixel + if (dasher.on()) { + uint alpha = (quint8)(y >> 8); + drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6); + drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6); + } + dasher.adjust(); + y += yinc; + ++x; + // draw line + if (x < xs) { + do { + if (dasher.on()) { + uint alpha = (quint8)(y >> 8); + drawPixel(stroker, x, y>>16, (255-alpha)); + drawPixel(stroker, x, (y>>16) + 1, alpha); + } + dasher.adjust(); + y += yinc; + } while (++x < xs); + } + // draw last pixel + if (alphaEnd && dasher.on()) { + uint alpha = (quint8)(y >> 8); + drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6); + drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6); + } + } +} diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h new file mode 100644 index 0000000..bc6dd76 --- /dev/null +++ b/src/gui/painting/qcosmeticstroker_p.h @@ -0,0 +1,101 @@ +#ifndef QCOSMETICSTROKER_P_H +#define QCOSMETICSTROKER_P_H + +#include +#include +#include +#include + +class QCosmeticStroker; + + +typedef void (*StrokeLine)(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps); + +class QCosmeticStroker +{ +public: + struct Point { + int x; + int y; + }; + struct PointF { + qreal x; + qreal y; + }; + + enum Caps { + NoCaps = 0, + CapBegin = 0x1, + CapEnd = 0x2, + }; + + // used to avoid drop outs or duplicated points + enum Direction { + TopToBottom, + BottomToTop, + LeftToRight, + RightToLeft + }; + + QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr) + : state(s), + clip(dr), + pattern(0), + reversePattern(0), + patternSize(0), + patternLength(0), + patternOffset(0), + current_span(0), + lastDir(LeftToRight), + lastAxisAligned(false) + { setup(); } + ~QCosmeticStroker() { free(pattern); free(reversePattern); } + void drawLine(const QPointF &p1, const QPointF &p2); + void drawPath(const QVectorPath &path); + void drawPoints(const QPoint *points, int num); + void drawPoints(const QPointF *points, int num); + + + QRasterPaintEngineState *state; + QRect clip; + // clip bounds in real + qreal xmin, xmax; + qreal ymin, ymax; + + StrokeLine stroke; + bool drawCaps; + + int *pattern; + int *reversePattern; + int patternSize; + int patternLength; + int patternOffset; + + enum { NSPANS = 255 }; + QT_FT_Span spans[NSPANS]; + int current_span; + ProcessSpans blend; + + int opacity; + + uint color; + uint *pixels; + int ppl; + + Direction lastDir; + Point lastPixel; + bool lastAxisAligned; + +private: + void setup(); + + void renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps); + void renderCubicSubdivision(PointF *points, int level, int caps); + // used for closed subpaths + void calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2); + +public: + bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2); +}; + +#endif // QCOSMETICLINE_H diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 2119e30..f0bc0d6 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -69,6 +69,7 @@ // #include #include #include +#include #include "qmemrotate_p.h" #include "qpaintengine_raster_p.h" @@ -156,20 +157,6 @@ enum LineDrawMode { LineDrawIncludeLastPixel }; -static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &rect); -static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2, - QPen *pen, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect, - int *patternOffset); -// static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2, -// ProcessSpans span_func, QSpanData *data, -// LineDrawMode style, const QRect &devRect); - -static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, - ProcessSpans pen_func, ProcessSpans brush_func, - QSpanData *pen_data, QSpanData *brush_data); - struct QRasterFloatPoint { qreal x; qreal y; @@ -789,14 +776,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen) s->stroker = 0; } + ensureState(); // needed because of tx_noshear... s->flags.fast_pen = pen_style > Qt::NoPen - && s->penData.blend - && !s->flags.antialiased - && (penWidth == 0 || (penWidth <= 1 - && (s->matrix.type() <= QTransform::TxTranslate - || pen.isCosmetic()))); + && s->penData.blend + && ((pen.isCosmetic() && penWidth <= 1) + || (s->flags.tx_noshear && penWidth * s->txscale <= 1)); - ensureState(); // needed because of tx_noshear... s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear; s->strokeFlags = 0; @@ -1513,6 +1498,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount); #endif Q_D(QRasterPaintEngine); + ensureState(); QRasterPaintEngineState *s = state(); // Fill @@ -1541,32 +1527,14 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) ensurePen(); if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) { - const QRect *r = rects; - const QRect *lastRect = rects + rectCount; - while (r < lastRect) { - int left = r->x(); - int right = r->x() + r->width(); - int top = r->y(); - int bottom = r->y() + r->height(); - -#ifdef Q_WS_MAC - int pts[] = { top, left, - top, right, - bottom, right, - bottom, left }; -#else - int pts[] = { left, top, - right, top, - right, bottom, - left, bottom }; -#endif - - strokePolygonCosmetic((QPoint *) pts, 4, WindingMode); - ++r; + QRectVectorPath path; + if (s->flags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); + for (int i = 0; i < rectCount; ++i) { + path.set(rects[i]); + stroker.drawPath(path); } } else { - QRectVectorPath path; for (int i = 0; i < rectCount; ++i) { path.set(rects[i]); stroke(path, s->pen); @@ -1581,13 +1549,13 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) { #ifdef QT_DEBUG_DRAW - qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount); + qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount); #endif #ifdef QT_FAST_SPANS Q_D(QRasterPaintEngine); + ensureState(); QRasterPaintEngineState *s = state(); - ensureState(); if (s->flags.tx_noshear) { ensureBrush(); @@ -1605,59 +1573,17 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) ensurePen(); if (s->penData.blend) { - qreal width = s->pen.isCosmetic() - ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF()) - : s->lastPen.widthF() * s->txscale; - - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) { - for (int i = 0; i < rectCount; ++i) { - const QRectF &r = rects[i]; - qreal left = r.x(); - qreal right = r.x() + r.width(); - qreal top = r.y(); - qreal bottom = r.y() + r.height(); - qreal pts[] = { left, top, - right, top, - right, bottom, - left, bottom }; - strokePolygonCosmetic((QPointF *) pts, 4, WindingMode); - } - } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) { - d->initializeRasterizer(&s->penData); - + QRectVectorPath path; + if (s->flags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); for (int i = 0; i < rectCount; ++i) { - const QRectF &rect = rects[i].normalized(); - if (rect.isEmpty()) { - qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() }; - QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint); - QPaintEngineEx::stroke(vp, s->lastPen); - } else { - const QPointF tl = s->matrix.map(rect.topLeft()); - const QPointF tr = s->matrix.map(rect.topRight()); - const QPointF bl = s->matrix.map(rect.bottomLeft()); - const QPointF br = s->matrix.map(rect.bottomRight()); - const qreal w = width / (rect.width() * s->txscale); - const qreal h = width / (rect.height() * s->txscale); - d->rasterizer->rasterizeLine(tl, tr, w); // top - d->rasterizer->rasterizeLine(bl, br, w); // bottom - d->rasterizer->rasterizeLine(bl, tl, h); // left - d->rasterizer->rasterizeLine(br, tr, h); // right - } + path.set(rects[i]); + stroker.drawPath(path); } } else { for (int i = 0; i < rectCount; ++i) { - const QRectF &r = rects[i]; - qreal left = r.x(); - qreal right = r.x() + r.width(); - qreal top = r.y(); - qreal bottom = r.y() + r.height(); - qreal pts[] = { left, top, - right, top, - right, bottom, - left, bottom, - left, top }; - QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint); - QPaintEngineEx::stroke(vp, s->lastPen); + path.set(rects[i]); + QPaintEngineEx::stroke(path, s->lastPen); } } } @@ -1674,36 +1600,16 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) */ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) { + Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); + ensurePen(pen); if (!s->penData.blend) return; - if (s->flags.fast_pen && !path.isCurved() - && s->lastPen.brush().isOpaque()) { - int count = path.elementCount(); - QPointF *points = (QPointF *) path.points(); - const QPainterPath::ElementType *types = path.elements(); - if (types) { - int first = 0; - int last; - while (first < count) { - while (first < count && types[first] != QPainterPath::MoveToElement) ++first; - last = first + 1; - while (last < count && types[last] == QPainterPath::LineToElement) ++last; - strokePolygonCosmetic(points + first, last - first, - path.hasImplicitClose() && last == count // only close last one.. - ? WindingMode - : PolylineMode); - first = last; - } - } else { - strokePolygonCosmetic(points, count, - path.hasImplicitClose() - ? WindingMode - : PolylineMode); - } - + if (s->flags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); + stroker.drawPath(path); } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) { qreal width = s->lastPen.isCosmetic() ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen)) @@ -1818,26 +1724,6 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) } } - if (path.shape() == QVectorPath::EllipseHint) { - if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) { - const qreal *p = path.points(); - QPointF tl = QPointF(p[0], p[1]) * s->matrix; - QPointF br = QPointF(p[4], p[5]) * s->matrix; - QRectF r = s->matrix.mapRect(QRectF(tl, br)); - - ProcessSpans penBlend = d->getPenFunc(r, &s->penData); - ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData); - const QRect brect = QRect(int(r.x()), int(r.y()), - int_dim(r.x(), r.width()), - int_dim(r.y(), r.height())); - if (brect == r) { - drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend, - &s->penData, &s->brushData); - return; - } - } - } - // ### Optimize for non transformed ellipses and rectangles... QRectF cpRect = path.controlPointRect(); const QRect deviceRect = s->matrix.mapRect(cpRect).toRect(); @@ -2032,6 +1918,7 @@ void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, Poly */ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { + Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); #ifdef QT_DEBUG_DRAW @@ -2048,9 +1935,9 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly } ensurePen(); - ensureBrush(); if (mode != PolylineMode) { // Do the fill... + ensureBrush(); if (s->brushData.blend) { fillPolygon(points, pointCount, mode); } @@ -2058,10 +1945,11 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly // Do the outline... if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) - strokePolygonCosmetic(points, pointCount, mode); - else { - QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode)); + QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode)); + if (s->flags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); + stroker.drawPath(vp); + } else { QPaintEngineEx::stroke(vp, s->lastPen); } } @@ -2090,13 +1978,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg return; } - ensureState(); ensurePen(); - if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) { - // this calls the float version - QPaintEngineEx::drawPolygon(points, pointCount, mode); - return; - } // Do the fill if (mode != PolylineMode) { @@ -2122,230 +2004,24 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg // Do the outline... if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) - strokePolygonCosmetic(points, pointCount, mode); - else { - int count = pointCount * 2; - QVarLengthArray fpoints(count); -#ifdef Q_WS_MAC - for (int i=0; ilastPen); - } - } -} - -/*! - \internal -*/ -void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode) -{ - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - Q_ASSERT(s->penData.blend); - Q_ASSERT(s->flags.fast_pen); - - bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1]; - - // Use fast path for 0 width / trivial pens. - QIntRect devRect; - devRect.set(d->deviceRect); - - LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap - ? LineDrawIncludeLastPixel - : LineDrawNormal); - int dashOffset = int(s->lastPen.dashOffset()); - - // Draw all the line segments. - for (int i=1; imatrix; - QPointF lp2 = points[i] * s->matrix; - - const QRectF brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) { - drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - } else { - drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); + int count = pointCount * 2; + QVarLengthArray fpoints(count); + #ifdef Q_WS_MAC + for (int i=0; imatrix; - QPointF lp2 = points[0] * s->matrix; - - const QRectF brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) { - drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - penBlend, &s->penData, - LineDrawIncludeLastPixel, - devRect); + #else + for (int i=0; iflags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); + stroker.drawPath(vp); } else { - drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - &s->lastPen, - penBlend, &s->penData, - LineDrawIncludeLastPixel, - devRect, &dashOffset); - } - } - -} - -/*! - \internal -*/ -void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode) -{ - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - // We assert here because this function is called from drawRects - // and drawPolygon and they already do ensurePen(), so we skip that - // here to avoid duplicate checks.. - Q_ASSERT(s->penData.blend); - - bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1]; - - QIntRect devRect; - devRect.set(d->deviceRect); - - LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap - ? LineDrawIncludeLastPixel - : LineDrawNormal); - - int m11 = int(s->matrix.m11()); - int m22 = int(s->matrix.m22()); - int dx = int(s->matrix.dx()); - int dy = int(s->matrix.dy()); - int m13 = int(s->matrix.m13()); - int m23 = int(s->matrix.m23()); - bool affine = !m13 && !m23; - - int dashOffset = int(s->lastPen.dashOffset()); - - if (affine) { - // Draw all the line segments. - for (int i=1; imatrix; - const QPoint lp2 = points[i] * s->matrix; - const QRect brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); - - } - - // Polygons are implicitly closed. - if (needs_closing) { - const QPoint lp1 = points[pointCount - 1] * s->matrix; - const QPoint lp2 = points[0] * s->matrix; - const QRect brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - &s->lastPen, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect, &dashOffset); - } - } else { - // Draw all the line segments. - for (int i=1; igetPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); - - } - - int x1 = points[pointCount-1].x() * m11 + dx; - int y1 = points[pointCount-1].y() * m22 + dy; - qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.; - w = 1/w; - x1 = int(x1*w); - y1 = int(y1*w); - int x2 = points[0].x() * m11 + dx; - int y2 = points[0].y() * m22 + dy; - w = m13*points[0].x() + m23*points[0].y() + 1.; - w = 1/w; - x2 = int(x2 * w); - y2 = int(y2 * w); - // Polygons are implicitly closed. - - if (needs_closing) { - const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect, &dashOffset); + QPaintEngineEx::stroke(vp, s->lastPen); } } } @@ -3345,32 +3021,6 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect, return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend; } -inline ProcessSpans -QRasterPaintEnginePrivate::getPenFunc(const QRect &rect, - const QSpanData *data) const -{ - Q_Q(const QRasterPaintEngine); - const QRasterPaintEngineState *s = q->state(); - - if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate) - return data->blend; - const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->pen.widthF()); - return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; -} - -inline ProcessSpans -QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, - const QSpanData *data) const -{ - Q_Q(const QRasterPaintEngine); - const QRasterPaintEngineState *s = q->state(); - - if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate) - return data->blend; - const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF()); - return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; -} - /*! \reimp */ @@ -3544,48 +3194,16 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount) QRasterPaintEngineState *s = state(); ensurePen(); - qreal pw = s->lastPen.widthF(); - if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) { - QPaintEngineEx::drawPoints(points, pointCount); - - } else { - if (!s->penData.blend) - return; - - QVarLengthArray array(pointCount); - QT_FT_Span span = { 0, 1, 0, 255 }; - const QPointF *end = points + pointCount; - qreal trans_x, trans_y; - int x, y; - int left = d->deviceRect.x(); - int right = left + d->deviceRect.width(); - int top = d->deviceRect.y(); - int bottom = top + d->deviceRect.height(); - int count = 0; - while (points < end) { - s->matrix.map(points->x(), points->y(), &trans_x, &trans_y); - x = qFloor(trans_x); - y = qFloor(trans_y); - if (x >= left && x < right && y >= top && y < bottom) { - if (count > 0) { - const QT_FT_Span &last = array[count - 1]; - // spans must be sorted on y (primary) and x (secondary) - if (y < last.y || (y == last.y && x < last.x)) { - s->penData.blend(count, array.constData(), &s->penData); - count = 0; - } - } - - span.x = x; - span.y = y; - array[count++] = span; - } - ++points; - } + if (!s->penData.blend) + return; - if (count > 0) - s->penData.blend(count, array.constData(), &s->penData); + if (!s->flags.fast_pen) { + QPaintEngineEx::drawPoints(points, pointCount); + return; } + + QCosmeticStroker stroker(s, d->deviceRect); + stroker.drawPoints(points, pointCount); } @@ -3595,48 +3213,16 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) QRasterPaintEngineState *s = state(); ensurePen(); - double pw = s->lastPen.widthF(); - if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) { - QPaintEngineEx::drawPoints(points, pointCount); - - } else { - if (!s->penData.blend) - return; - - QVarLengthArray array(pointCount); - QT_FT_Span span = { 0, 1, 0, 255 }; - const QPoint *end = points + pointCount; - qreal trans_x, trans_y; - int x, y; - int left = d->deviceRect.x(); - int right = left + d->deviceRect.width(); - int top = d->deviceRect.y(); - int bottom = top + d->deviceRect.height(); - int count = 0; - while (points < end) { - s->matrix.map(points->x(), points->y(), &trans_x, &trans_y); - x = qFloor(trans_x); - y = qFloor(trans_y); - if (x >= left && x < right && y >= top && y < bottom) { - if (count > 0) { - const QT_FT_Span &last = array[count - 1]; - // spans must be sorted on y (primary) and x (secondary) - if (y < last.y || (y == last.y && x < last.x)) { - s->penData.blend(count, array.constData(), &s->penData); - count = 0; - } - } - - span.x = x; - span.y = y; - array[count++] = span; - } - ++points; - } + if (!s->penData.blend) + return; - if (count > 0) - s->penData.blend(count, array.constData(), &s->penData); + if (!s->flags.fast_pen) { + QPaintEngineEx::drawPoints(points, pointCount); + return; } + + QCosmeticStroker stroker(s, d->deviceRect); + stroker.drawPoints(points, pointCount); } /*! @@ -3645,59 +3231,22 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount) { #ifdef QT_DEBUG_DRAW - qDebug() << " - QRasterPaintEngine::drawLine()"; + qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount; #endif Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); ensurePen(); + if (!s->penData.blend) + return; + if (s->flags.fast_pen) { - QIntRect bounds; bounds.set(d->deviceRect); - LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap - ? LineDrawNormal - : LineDrawIncludeLastPixel; - - int m11 = int(s->matrix.m11()); - int m22 = int(s->matrix.m22()); - int dx = qFloor(s->matrix.dx()); - int dy = qFloor(s->matrix.dy()); + QCosmeticStroker stroker(s, d->deviceRect); for (int i=0; ilastPen.dashOffset()); - if (s->flags.int_xform) { - const QLine &l = lines[i]; - int x1 = l.x1() * m11 + dx; - int y1 = l.y1() * m22 + dy; - int x2 = l.x2() * m11 + dx; - int y2 = l.y2() * m22 + dy; - - const QRect brect(QPoint(x1, y1), QPoint(x2, y2)); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, penBlend, - &s->penData, mode, bounds, - &dashOffset); - } else { - QLineF line = lines[i] * s->matrix; - const QRectF brect(QPointF(line.x1(), line.y1()), - QPointF(line.x2(), line.y2())); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - &s->lastPen, penBlend, - &s->penData, mode, bounds, - &dashOffset); - } + const QLine &l = lines[i]; + stroker.drawLine(l.p1(), l.p2()); } - } else if (s->penData.blend) { + } else { QPaintEngineEx::drawLines(lines, lineCount); } } @@ -3754,7 +3303,7 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line, void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) { #ifdef QT_DEBUG_DRAW - qDebug() << " - QRasterPaintEngine::drawLine()"; + qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount; #endif Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); @@ -3763,28 +3312,10 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) if (!s->penData.blend) return; if (s->flags.fast_pen) { - QIntRect bounds; - bounds.set(d->deviceRect); - LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap - ? LineDrawNormal - : LineDrawIncludeLastPixel; - + QCosmeticStroker stroker(s, d->deviceRect); for (int i=0; ilastPen.dashOffset()); - QLineF line = lines[i] * s->matrix; - const QRectF brect(QPointF(line.x1(), line.y1()), - QPointF(line.x2(), line.y2())); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - &s->lastPen, - penBlend, &s->penData, mode, - bounds, &dashOffset); + QLineF line = lines[i]; + stroker.drawLine(line.p1(), line.p2()); } } else { QPaintEngineEx::drawLines(lines, lineCount); @@ -3797,29 +3328,6 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) */ void QRasterPaintEngine::drawEllipse(const QRectF &rect) { - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - ensurePen(); - if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen) - || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased)) - && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT - && !rect.isEmpty() - && s->matrix.type() <= QTransform::TxScale) // no shear - { - ensureBrush(); - const QRectF r = s->matrix.mapRect(rect); - ProcessSpans penBlend = d->getPenFunc(r, &s->penData); - ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData); - const QRect brect = QRect(int(r.x()), int(r.y()), - int_dim(r.x(), r.width()), - int_dim(r.y(), r.height())); - if (brect == r) { - drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend, - &s->penData, &s->brushData); - return; - } - } QPaintEngineEx::drawEllipse(rect); } @@ -4821,7 +4329,7 @@ static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userDa while (spans < end) { QSpan *clipped = cspans; spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS); -// qDebug() << "processed " << processed << "clipped" << clipped-cspans +// qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage; if (clipped - cspans) @@ -5473,878 +4981,6 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _ adjustSpanMethods(); } -#ifdef Q_WS_WIN - - -#endif - - -/*! - \internal - - Draws a line using the floating point midpoint algorithm. The line - \a line is already in device coords at this point. -*/ - -static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect) -{ -#ifdef QT_DEBUG_DRAW - qDebug() << " - drawLine_midpoint_i" << QLine(QPoint(x1, y1), QPoint(x2, y2)); -#endif - - int x, y; - int dx, dy, d, incrE, incrNE; - - dx = x2 - x1; - dy = y2 - y1; - - const int NSPANS = 256; - QT_FT_Span spans[NSPANS]; - int current = 0; - bool ordered = true; - - if (dy == 0) { - // specialcase horizontal lines - if (y1 >= devRect.y1 && y1 < devRect.y2) { - int start = qMax(devRect.x1, qMin(x1, x2)); - int stop = qMax(x1, x2) + 1; - int stop_clipped = qMin(devRect.x2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - if (len > 0) { - spans[0].x = ushort(start); - spans[0].len = ushort(len); - spans[0].y = y1; - spans[0].coverage = 255; - span_func(1, spans, data); - } - } - return; - } else if (dx == 0) { - // specialcase vertical lines - if (x1 >= devRect.x1 && x1 < devRect.x2) { - int start = qMax(devRect.y1, qMin(y1, y2)); - int stop = qMax(y1, y2) + 1; - int stop_clipped = qMin(devRect.y2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - // hw: create spans directly instead to possibly avoid clipping - if (len > 0) - fillRect_normalized(QRect(x1, start, 1, len).normalized(), data, 0); - } - return; - } - - - if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */ - - if (x2 < x1) { /* if coordinates are out of order */ - qt_swap_int(x1, x2); - dx = -dx; - - qt_swap_int(y1, y2); - dy = -dy; - } - - int x_lower_limit = - 128; - if (x1 < x_lower_limit) { - int cy = dy * (x_lower_limit - x1) / dx + y1; - drawLine_midpoint_i(x_lower_limit, cy, x2, y2, span_func, data, style, devRect); - return; - } - - if (style == LineDrawNormal) - --x2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - x2 = qMin(x2, devRect.x2 - 1); - - // completely clipped, so abort - if (x2 <= x1) { - return; - } - - int x = x1; - int y = y1; - - if (y2 <= y1) - ordered = false; - - { - const int index = (ordered ? current : NSPANS - 1 - current); - spans[index].coverage = 255; - spans[index].x = x; - spans[index].y = y; - - if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) - spans[index].len = 1; - else - spans[index].len = 0; - } - - if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees) - y2 = qMin(y2, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE - dx; - incrNE = (dy - dx) * 2; - - if (y > y2) - goto flush_and_return; - - while (x < x2) { - ++x; - if (d > 0) { - if (spans[current].len > 0) - ++current; - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - - ++y; - d += incrNE; - if (y > y2) - goto flush_and_return; - - spans[current].len = 0; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - } else { - d += incrE; - if (x == devRect.x1) - spans[current].x = devRect.x1; - } - - if (x < devRect.x1 || y < devRect.y1) - continue; - - Q_ASSERT(x 0) { - ++current; - } - } else { // 0-45 and 180->225 (unit circle degrees) - - y1 = qMin(y1, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE + dx; - incrNE = (dy + dx) * 2; - - if (y < devRect.y1) - goto flush_and_return; - - while (x < x2) { - ++x; - if (d < 0) { - if (spans[NSPANS - 1 - current].len > 0) - ++current; - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - - --y; - d += incrNE; - if (y < devRect.y1) - goto flush_and_return; - - const int index = NSPANS - 1 - current; - spans[index].len = 0; - spans[index].coverage = 255; - spans[index].x = x; - spans[index].y = y; - } else { - d += incrE; - if (x == devRect.x1) - spans[NSPANS - 1 - current].x = devRect.x1; - } - - if (x < devRect.x1 || y > y1) - continue; - - Q_ASSERT(x 0) { - ++current; - } - } - - } else { - - // if y is the major axis: - - if (y2 < y1) { /* if coordinates are out of order */ - qt_swap_int(y1, y2); - dy = -dy; - - qt_swap_int(x1, x2); - dx = -dx; - } - - int y_lower_limit = - 128; - if (y1 < y_lower_limit) { - int cx = dx * (y_lower_limit - y1) / dy + x1; - drawLine_midpoint_i(cx, y_lower_limit, x2, y2, span_func, data, style, devRect); - return; - } - - if (style == LineDrawNormal) - --y2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - y2 = qMin(y2, devRect.y2 - 1); - - // completely clipped, so abort - if (y2 <= y1) { - return; - } - - x = x1; - y = y1; - - if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) { - Q_ASSERT(x >= devRect.x1 && y >= devRect.y1 && x < devRect.x2 && y < devRect.y2); - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - - if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees) - x2 = qMin(x2, devRect.x2 - 1); - incrE = dx * 2; - d = incrE - dy; - incrNE = (dx - dy) * 2; - - if (x > x2) - goto flush_and_return; - - while (y < y2) { - if (d > 0) { - ++x; - d += incrNE; - if (x > x2) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - if (x < devRect.x1 || y < devRect.y1) - continue; - Q_ASSERT(x 90 and 225 -> 270 (unit circle degrees) - x1 = qMin(x1, devRect.x2 - 1); - incrE = dx * 2; - d = incrE + dy; - incrNE = (dx + dy) * 2; - - if (x < devRect.x1) - goto flush_and_return; - - while (y < y2) { - if (d < 0) { - --x; - d += incrNE; - if (x < devRect.x1) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - if (y < devRect.y1 || x > x1) - continue; - Q_ASSERT(x>=devRect.x1 && x=devRect.y1 && y 0) - span_func(current, ordered ? spans : spans + (NSPANS - current), data); -} - -static void offset_pattern(int offset, bool *inDash, int *dashIndex, int *currentOffset, const QVarLengthArray &pattern) -{ - while (offset--) { - if (--*currentOffset == 0) { - *inDash = !*inDash; - *dashIndex = ((*dashIndex + 1) % pattern.size()); - *currentOffset = int(pattern[*dashIndex]); - } - } -} - -static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2, - QPen *pen, - ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect, - int *patternOffset) -{ -#ifdef QT_DEBUG_DRAW - qDebug() << " - drawLine_midpoint_dashed_i" << x1 << y1 << x2 << y2 << *patternOffset; -#endif - - int x, y; - int dx, dy, d, incrE, incrNE; - - dx = x2 - x1; - dy = y2 - y1; - - Q_ASSERT(*patternOffset >= 0); - - const QVector penPattern = pen->dashPattern(); - QVarLengthArray pattern(penPattern.size()); - - int patternLength = 0; - for (int i = 0; i < penPattern.size(); ++i) - patternLength += qMax(1.0, (penPattern.at(i))); - - // pattern must be reversed if coordinates are out of order - int reverseLength = -1; - if (dy == 0 && x1 > x2) - reverseLength = x1 - x2; - else if (dx == 0 && y1 > y2) - reverseLength = y1 - y2; - else if (qAbs(dx) >= qAbs(dy) && x2 < x1) // x major axis - reverseLength = qAbs(dx); - else if (qAbs(dy) >= qAbs(dx) && y2 < y1) // y major axis - reverseLength = qAbs(dy); - - const bool reversed = (reverseLength > -1); - if (reversed) { // reverse pattern - for (int i = 0; i < penPattern.size(); ++i) - pattern[penPattern.size() - 1 - i] = qMax(1.0, penPattern.at(i)); - - *patternOffset = (patternLength - 1 - *patternOffset); - *patternOffset += patternLength - (reverseLength % patternLength); - *patternOffset = *patternOffset % patternLength; - } else { - for (int i = 0; i < penPattern.size(); ++i) - pattern[i] = qMax(1.0, penPattern.at(i)); - } - - int dashIndex = 0; - bool inDash = !reversed; - int currPattern = int(pattern[dashIndex]); - - // adjust pattern for offset - offset_pattern(*patternOffset, &inDash, &dashIndex, &currPattern, pattern); - - const int NSPANS = 256; - QT_FT_Span spans[NSPANS]; - int current = 0; - bool ordered = true; - - if (dy == 0) { - // specialcase horizontal lines - if (y1 >= devRect.y1 && y1 < devRect.y2) { - int start_unclipped = qMin(x1, x2); - int start = qMax(devRect.x1, start_unclipped); - int stop = qMax(x1, x2) + 1; - int stop_clipped = qMin(devRect.x2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - - // adjust pattern for starting offset - offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern); - - if (len > 0) { - int x = start; - while (x < stop_clipped) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - const int dash = qMin(currPattern, stop_clipped - x); - if (inDash) { - spans[current].x = ushort(x); - spans[current].len = ushort(dash); - spans[current].y = y1; - spans[current].coverage = 255; - ++current; - } - if (dash < currPattern) { - currPattern -= dash; - } else { - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - inDash = !inDash; - } - x += dash; - } - } - } - goto flush_and_return; - } else if (dx == 0) { - if (x1 >= devRect.x1 && x1 < devRect.x2) { - int start_unclipped = qMin(y1, y2); - int start = qMax(devRect.y1, start_unclipped); - int stop = qMax(y1, y2) + 1; - int stop_clipped = qMin(devRect.y2, stop); - if (style == LineDrawNormal && stop == stop_clipped) - --stop; - else - stop = stop_clipped; - - // adjust pattern for starting offset - offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern); - - // loop over dashes - int y = start; - while (y < stop) { - const int dash = qMin(currPattern, stop - y); - if (inDash) { - for (int i = 0; i < dash; ++i) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].x = x1; - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].y = ushort(y + i); - ++current; - } - } - if (dash < currPattern) { - currPattern -= dash; - } else { - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - inDash = !inDash; - } - y += dash; - } - } - goto flush_and_return; - } - - if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */ - - if (x2 < x1) { /* if coordinates are out of order */ - qt_swap_int(x1, x2); - dx = -dx; - - qt_swap_int(y1, y2); - dy = -dy; - } - - if (style == LineDrawNormal) - --x2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - x2 = qMin(x2, devRect.x2 - 1); - - // completely clipped, so abort - if (x2 <= x1) - goto flush_and_return; - - int x = x1; - int y = y1; - - if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) { - Q_ASSERT(x < devRect.x2); - if (inDash) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - - if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees) - y2 = qMin(y2, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE - dx; - incrNE = (dy - dx) * 2; - - if (y > y2) - goto flush_and_return; - - while (x < x2) { - if (d > 0) { - ++y; - d += incrNE; - if (y > y2) - goto flush_and_return; - } else { - d += incrE; - } - ++x; - - const bool skip = x < devRect.x1 || y < devRect.y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } else { // 0-45 and 180->225 (unit circle degrees) - y1 = qMin(y1, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE + dx; - incrNE = (dy + dx) * 2; - - if (y < devRect.y1) - goto flush_and_return; - - while (x < x2) { - if (d < 0) { - if (current > 0) { - span_func(current, spans, data); - current = 0; - } - - --y; - d += incrNE; - if (y < devRect.y1) - goto flush_and_return; - } else { - d += incrE; - } - ++x; - - const bool skip = x < devRect.x1 || y > y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } - } else { - - // if y is the major axis: - - if (y2 < y1) { /* if coordinates are out of order */ - qt_swap_int(y1, y2); - dy = -dy; - - qt_swap_int(x1, x2); - dx = -dx; - } - - if (style == LineDrawNormal) - --y2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - y2 = qMin(y2, devRect.y2 - 1); - - // completely clipped, so abort - if (y2 <= y1) - goto flush_and_return; - - x = x1; - y = y1; - - if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) { - Q_ASSERT(x < devRect.x2); - if (inDash) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - - if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees) - x2 = qMin(x2, devRect.x2 - 1); - incrE = dx * 2; - d = incrE - dy; - incrNE = (dx - dy) * 2; - - if (x > x2) - goto flush_and_return; - - while (y < y2) { - if (d > 0) { - ++x; - d += incrNE; - if (x > x2) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - const bool skip = x < devRect.x1 || y < devRect.y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } else { // 45 -> 90 and 225 -> 270 (unit circle degrees) - x1 = qMin(x1, devRect.x2 - 1); - incrE = dx * 2; - d = incrE + dy; - incrNE = (dx + dy) * 2; - - if (x < devRect.x1) - goto flush_and_return; - - while (y < y2) { - if (d < 0) { - --x; - d += incrNE; - if (x < devRect.x1) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - const bool skip = y < devRect.y1 || x > x1; - Q_ASSERT(skip || (x >= devRect.x1 && x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } - } -flush_and_return: - if (current > 0) - span_func(current, ordered ? spans : spans + (NSPANS - current), data); - - // adjust offset - if (reversed) { - *patternOffset = (patternLength - 1 - *patternOffset); - } else { - *patternOffset = 0; - for (int i = 0; i <= dashIndex; ++i) - *patternOffset += int(pattern[i]); - *patternOffset += patternLength - currPattern - 1; - *patternOffset = (*patternOffset % patternLength); - } -} - -/*! - \internal - \a x and \a y is relative to the midpoint of \a rect. -*/ -static inline void drawEllipsePoints(int x, int y, int length, - const QRect &rect, - const QRect &clip, - ProcessSpans pen_func, ProcessSpans brush_func, - QSpanData *pen_data, QSpanData *brush_data) -{ - if (length == 0) - return; - - QT_FT_Span outline[4]; - const int midx = rect.x() + (rect.width() + 1) / 2; - const int midy = rect.y() + (rect.height() + 1) / 2; - - x = x + midx; - y = midy - y; - - // topleft - outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1); - outline[0].len = qMin(length, x - outline[0].x); - outline[0].y = y; - outline[0].coverage = 255; - - // topright - outline[1].x = x; - outline[1].len = length; - outline[1].y = y; - outline[1].coverage = 255; - - // bottomleft - outline[2].x = outline[0].x; - outline[2].len = outline[0].len; - outline[2].y = midy + (midy - y) - (rect.height() & 0x1); - outline[2].coverage = 255; - - // bottomright - outline[3].x = x; - outline[3].len = length; - outline[3].y = outline[2].y; - outline[3].coverage = 255; - - if (brush_func && outline[0].x + outline[0].len < outline[1].x) { - QT_FT_Span fill[2]; - - // top fill - fill[0].x = outline[0].x + outline[0].len - 1; - fill[0].len = qMax(0, outline[1].x - fill[0].x); - fill[0].y = outline[1].y; - fill[0].coverage = 255; - - // bottom fill - fill[1].x = outline[2].x + outline[2].len - 1; - fill[1].len = qMax(0, outline[3].x - fill[1].x); - fill[1].y = outline[3].y; - fill[1].coverage = 255; - - int n = (fill[0].y >= fill[1].y ? 1 : 2); - n = qt_intersect_spans(fill, n, clip); - if (n > 0) - brush_func(n, fill, brush_data); - } - if (pen_func) { - int n = (outline[1].y >= outline[2].y ? 2 : 4); - n = qt_intersect_spans(outline, n, clip); - if (n > 0) - pen_func(n, outline, pen_data); - } -} - -/*! - \internal - Draws an ellipse using the integer point midpoint algorithm. -*/ -static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, - ProcessSpans pen_func, ProcessSpans brush_func, - QSpanData *pen_data, QSpanData *brush_data) -{ - const qreal a = qreal(rect.width()) / 2; - const qreal b = qreal(rect.height()) / 2; - qreal d = b*b - (a*a*b) + 0.25*a*a; - - int x = 0; - int y = (rect.height() + 1) / 2; - int startx = x; - - // region 1 - while (a*a*(2*y - 1) > 2*b*b*(x + 1)) { - if (d < 0) { // select E - d += b*b*(2*x + 3); - ++x; - } else { // select SE - d += b*b*(2*x + 3) + a*a*(-2*y + 2); - drawEllipsePoints(startx, y, x - startx + 1, rect, clip, - pen_func, brush_func, pen_data, brush_data); - startx = ++x; - --y; - } - } - drawEllipsePoints(startx, y, x - startx + 1, rect, clip, - pen_func, brush_func, pen_data, brush_data); - - // region 2 - d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b); - const int miny = rect.height() & 0x1; - while (y > miny) { - if (d < 0) { // select SE - d += b*b*(2*x + 2) + a*a*(-2*y + 3); - ++x; - } else { // select S - d += a*a*(-2*y + 3); - } - --y; - drawEllipsePoints(x, y, 1, rect, clip, - pen_func, brush_func, pen_data, brush_data); - } -} /*! \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 52f51fa..122c2b8 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -196,9 +196,6 @@ public: void stroke(const QVectorPath &path, const QPen &pen); void fill(const QVectorPath &path, const QBrush &brush); - void strokePolygonCosmetic(const QPoint *pts, int pointCount, PolygonDrawMode mode); - void strokePolygonCosmetic(const QPointF *pt, int pointCount, PolygonDrawMode mode); - void clip(const QVectorPath &path, Qt::ClipOperation op); void clip(const QRect &rect, Qt::ClipOperation op); void clip(const QRegion ®ion, Qt::ClipOperation op); @@ -328,8 +325,6 @@ public: bool isUnclipped_normalized(const QRect &rect) const; bool isUnclipped(const QRect &rect, int penWidth) const; bool isUnclipped(const QRectF &rect, int penWidth) const; - ProcessSpans getPenFunc(const QRect &rect, const QSpanData *data) const; - ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const; ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const; ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 7f601eb..bbdf76f 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -831,7 +831,7 @@ void QPaintEngineEx::drawEllipse(const QRectF &r) int point_count = 0; x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count); - QVectorPath vp((qreal *) pts, point_count, qpaintengineex_ellipse_types, QVectorPath::EllipseHint); + QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint); draw(vp); } -- cgit v0.12 From 15a5eaf0eeb44833a052b6201171fca4b9e8f74e Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Thu, 12 May 2011 14:10:56 +0200 Subject: Clear confusion between QMainWindow and QMainWindowLayout. The variables activateUnifiedToolbarAfterFullScreen and useHIToolBar were implemented in both classes. This was an obvious bug, where variable would be initialized in one class and use in the other one. Task-number: QTBUG-18874 Reviewed-by: Yoann Lopes --- src/gui/widgets/qmainwindow.cpp | 2 -- src/gui/widgets/qmainwindowlayout.cpp | 1 + src/gui/widgets/qmainwindowlayout_p.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index 43d6796..e39e595 100644 --- a/src/gui/widgets/qmainwindow.cpp +++ b/src/gui/widgets/qmainwindow.cpp @@ -78,7 +78,6 @@ public: : layout(0), explicitIconSize(false), toolButtonStyle(Qt::ToolButtonIconOnly) #ifdef Q_WS_MAC , useHIToolBar(false) - , activateUnifiedToolbarAfterFullScreen(false) #endif #if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR) , hasOldCursor(false) , cursorAdjusted(false) @@ -90,7 +89,6 @@ public: Qt::ToolButtonStyle toolButtonStyle; #ifdef Q_WS_MAC bool useHIToolBar; - bool activateUnifiedToolbarAfterFullScreen; #endif void init(); QList hoverSeparator; diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index d4afe07..8880ca9 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -1699,6 +1699,7 @@ QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow, QLayout *parentLay , gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow)) #endif //QT_NO_RUBBERBAND #ifdef Q_WS_MAC + , activateUnifiedToolbarAfterFullScreen(false) , blockVisiblityCheck(false) #endif { diff --git a/src/gui/widgets/qmainwindowlayout_p.h b/src/gui/widgets/qmainwindowlayout_p.h index 20aca61..0442510 100644 --- a/src/gui/widgets/qmainwindowlayout_p.h +++ b/src/gui/widgets/qmainwindowlayout_p.h @@ -338,7 +338,6 @@ public: void removeFromMacToolbar(QToolBar *toolbar); void cleanUpMacToolbarItems(); void fixSizeInUnifiedToolbar(QToolBar *tb) const; - bool useHIToolBar; bool activateUnifiedToolbarAfterFullScreen; void syncUnifiedToolbarVisibility(); bool blockVisiblityCheck; -- cgit v0.12 From bff68fc7094a50af57f7da23ecf9b25cab00f188 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 12 May 2011 16:21:03 +0200 Subject: Fix compilation with namespaces enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Samuel Rødal --- src/gui/painting/qcosmeticstroker.cpp | 4 ++++ src/gui/painting/qcosmeticstroker_p.h | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 498b154..24d625e 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -3,6 +3,8 @@ #include #include +QT_BEGIN_NAMESPACE + #if 0 inline QString capString(int caps) { @@ -952,3 +954,5 @@ static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx } } } + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h index bc6dd76..1355a5a 100644 --- a/src/gui/painting/qcosmeticstroker_p.h +++ b/src/gui/painting/qcosmeticstroker_p.h @@ -6,6 +6,12 @@ #include #include +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + class QCosmeticStroker; @@ -98,4 +104,8 @@ public: bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2); }; +QT_END_NAMESPACE + +QT_END_HEADER + #endif // QCOSMETICLINE_H -- cgit v0.12 From 7a1c29f101b95c9cc2cb53f8b80d231b5a994a9a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 12 May 2011 19:00:15 +0200 Subject: fix compilation with namespaces --- src/gui/painting/qcosmeticstroker.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 24d625e..3ee262f 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -150,28 +150,28 @@ static StrokeLine strokeLine(int strokeSelection) switch (strokeSelection) { case Aliased|Solid|RegularDraw: - stroke = &::drawLine; + stroke = &QT_PREPEND_NAMESPACE(drawLine); break; case Aliased|Solid|FastDraw: - stroke = &::drawLine; + stroke = &QT_PREPEND_NAMESPACE(drawLine); break; case Aliased|Dashed|RegularDraw: - stroke = &::drawLine; + stroke = &QT_PREPEND_NAMESPACE(drawLine); break; case Aliased|Dashed|FastDraw: - stroke = &::drawLine; + stroke = &QT_PREPEND_NAMESPACE(drawLine); break; case AntiAliased|Solid|RegularDraw: - stroke = &drawLineAA; + stroke = &QT_PREPEND_NAMESPACE(drawLineAA); break; case AntiAliased|Solid|FastDraw: - stroke = &drawLineAA; + stroke = &QT_PREPEND_NAMESPACE(drawLineAA); break; case AntiAliased|Dashed|RegularDraw: - stroke = &drawLineAA; + stroke = &QT_PREPEND_NAMESPACE(drawLineAA); break; case AntiAliased|Dashed|FastDraw: - stroke = &drawLineAA; + stroke = &QT_PREPEND_NAMESPACE(drawLineAA); break; default: Q_ASSERT(false); -- cgit v0.12 From 4d5b8f66d82e9087d9d58a4e76e6b46ce7bb53cc Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Mon, 16 May 2011 10:20:54 +0200 Subject: Workaround a bug in Core Text to select Light fonts Currently in Core Text there is not proper way to select fonts with Light weight, for example: QFont font("Helvetica"); font.setWeight(QFont::Light); will give you Helvetica-Light, as with: QFont font("Helvetica"); font.setWeight(QFont::Normal); because of a bug in Core Text, applying 0 symbolic traits with CTFontCreateCopyWithSymbolicTraits will always return the Light variant of that font family. Thus, we should only do this unless symbolicTraits is not 0 or font.weight is not Normal (Light is not a symbolic trait, but CT doesn't support selecting Light weight numerically). Reviewed-by: Eskil --- src/gui/text/qfontengine_coretext.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index cbf51e6..d14db3a 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -100,7 +100,12 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QCFType descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize); QCFType baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, &transform); - ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits); + ctfont = NULL; + // There is a side effect in Core Text: if we apply 0 as symbolic traits to a font in normal weight, + // we will get the light version of that font (while the way supposed to work doesn't: + // setting kCTFontWeightTrait to some value between -1.0 to 0.0 has no effect on font selection) + if (fontDef.weight != QFont::Normal || symbolicTraits) + ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits); // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does // not exist for the given font. (for example italic) -- cgit v0.12 From 67d275542464c794ec4b650f10cca9a17e10c977 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 16 May 2011 16:07:10 +0200 Subject: fix autotest regressions introduced by 37c329a3 Add proper license headers and properly clip pixel drawing to the devices bounding rect. --- src/gui/painting/qcosmeticstroker.cpp | 45 +++++++++++++++++++++++++++++++++++ src/gui/painting/qcosmeticstroker_p.h | 41 +++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 3ee262f..d694b4b 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include "qcosmeticstroker_p.h" #include "private/qpainterpath_p.h" #include @@ -99,6 +140,10 @@ static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage) { + const QRect &cl = stroker->clip; + if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom()) + return; + int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ; int lasty = stroker->spans[stroker->current_span-1].y; diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h index 1355a5a..0aa71fc 100644 --- a/src/gui/painting/qcosmeticstroker_p.h +++ b/src/gui/painting/qcosmeticstroker_p.h @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QCOSMETICSTROKER_P_H #define QCOSMETICSTROKER_P_H -- cgit v0.12 From 0aa9b30432cec3b7f366983f451fc9a7f8f83243 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 18 May 2011 15:10:40 +0200 Subject: Fall back to using paths for large fonts in drawStaticText() QStaticText had an implicit risk which meant you had to make sure the text size did not grow unreasonably large. This was intended to avoid hiding the performance impact of using QStaticText for such a purpose, but it's too inconvenient. Thus, the same fall back as in drawTextItem() has been introduced. This will also fix a bug recently introduced when we started using the FT cache to draw static text in the raster engine, since this will fail for large fonts. Task-number: QTBUG-19084, QTBUG-19370 Reviewed-by: Jiang Jiang --- src/gui/painting/qpaintengine_raster.cpp | 12 ++++++-- src/gui/painting/qpaintengineex.cpp | 35 ++++++++++++++++++++++ src/gui/painting/qpaintengineex_p.h | 2 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 33 +++++++++++++------- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index f0bc0d6..4f8af48 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3029,8 +3029,16 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensurePen(); ensureState(); - drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, - textItem->fontEngine()); + QRasterPaintEngineState *s = state(); + + QFontEngine *fontEngine = textItem->fontEngine(); + const qreal pixelSize = fontEngine->fontDef.pixelSize; + if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) < 64 * 64) { + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, + fontEngine); + } else { + QPaintEngineEx::drawStaticTextItem(textItem); + } } /*! diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index bbdf76f..304e5fc 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -44,6 +44,8 @@ #include "qstroker_p.h" #include "qbezier_p.h" #include +#include +#include #include #include @@ -1057,5 +1059,38 @@ Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path) return p; } +void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem) +{ + QPainterPath path; +#ifndef Q_WS_MAC + path.setFillRule(Qt::WindingFill); +#endif + + if (staticTextItem->numGlyphs == 0) + return; + + QFontEngine *fontEngine = staticTextItem->fontEngine(); + fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions, + staticTextItem->numGlyphs, &path, 0); + if (!path.isEmpty()) { + QPainterState *s = state(); + QPainter::RenderHints oldHints = s->renderHints; + bool changedHints = false; + if (bool(oldHints & QPainter::TextAntialiasing) + && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias) + && !bool(oldHints & QPainter::Antialiasing)) { + s->renderHints |= QPainter::Antialiasing; + renderHintsChanged(); + changedHints = true; + } + + fill(qtVectorPathForPath(path), staticTextItem->color); + + if (changedHints) { + s->renderHints = oldHints; + renderHintsChanged(); + } + } +} QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index d12c602..7d57eee 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -202,7 +202,7 @@ public: virtual void updateState(const QPaintEngineState &state); - virtual void drawStaticTextItem(QStaticTextItem *) = 0; + virtual void drawStaticTextItem(QStaticTextItem *); virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast(QPaintEngine::state); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 38bd58d..3cf8faa 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1436,19 +1436,30 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) ensureActive(); - QFontEngineGlyphCache::Type glyphType = textItem->fontEngine()->glyphFormat >= 0 - ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) - : d->glyphCacheType; - if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { - if (d->device->alphaRequested() || state()->matrix.type() > QTransform::TxTranslate - || (state()->composition_mode != QPainter::CompositionMode_Source - && state()->composition_mode != QPainter::CompositionMode_SourceOver)) - { - glyphType = QFontEngineGlyphCache::Raster_A8; + QPainterState *s = state(); + float det = s->matrix.determinant(); + + // don't try to cache huge fonts or vastly transformed fonts + QFontEngine *fontEngine = textItem->fontEngine(); + const qreal pixelSize = fontEngine->fontDef.pixelSize; + if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || + det < 0.25f || det > 4.f) { + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) + : d->glyphCacheType; + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { + if (d->device->alphaRequested() || s->matrix.type() > QTransform::TxTranslate + || (s->composition_mode != QPainter::CompositionMode_Source + && s->composition_mode != QPainter::CompositionMode_SourceOver)) + { + glyphType = QFontEngineGlyphCache::Raster_A8; + } } - } - d->drawCachedGlyphs(glyphType, textItem); + d->drawCachedGlyphs(glyphType, textItem); + } else { + QPaintEngineEx::drawStaticTextItem(textItem); + } } bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) -- cgit v0.12 From 44e1526ee2585c0402c284aa94eb2472fa4a4145 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Wed, 18 May 2011 16:17:17 +0200 Subject: Change the flushing of the CGContext to a synchronization. When many NSView are being drawn, calling CGContextFlush() is too expensive and some flickering becomes apparent. We now call CGContextSynchronize() instead. Since this solves the flickering problem, we can now call setNeedsDisplay: for items in the unified toolbar. This allows us to smootly trigger many flushings inside the unified toolbar. Task-number: QTBUG-19267 Reviewed-by: Jiang Jiang --- src/gui/kernel/qcocoaview_mac.mm | 2 +- src/gui/painting/qunifiedtoolbarsurface_mac.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index b5e5d18..578970c 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -320,7 +320,7 @@ static int qCocoaViewCount = 0; } - CGContextFlush(context); + CGContextSynchronize(context); qt_mac_release_graphics_context(context); return; } diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp index 2fda6b9..94a7417 100644 --- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp +++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp @@ -171,10 +171,8 @@ void QUnifiedToolbarSurface::flush(QWidget *widget) if (!d->image) return; - if (widget->d_func()->flushRequested) { - // We call display: directly to avoid flickering in the toolbar. - qt_mac_display(widget); - } + if (widget->d_func()->flushRequested) + qt_mac_setNeedsDisplay(widget); } void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widget) -- cgit v0.12 From f8e85838c5531b56c2175cbdb9c24db426f7fd89 Mon Sep 17 00:00:00 2001 From: aavit Date: Thu, 19 May 2011 09:27:19 +0200 Subject: Revert "Fix how subpixel positions are intepreted in an aliased grid." This reverts commit 69fc9e594e6d5da87bff42707973683f84b67c93. Conflicts: src/gui/painting/qpaintengine_raster.cpp src/gui/painting/qrasterizer.cpp --- src/gui/painting/qoutlinemapper.cpp | 9 +++++++ src/gui/painting/qoutlinemapper_p.h | 8 ++++++- src/gui/painting/qpaintengine_raster.cpp | 40 ++++++++++++++++++++++---------- src/gui/painting/qrasterizer.cpp | 4 ++-- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp index aac5083..6e53c35 100644 --- a/src/gui/painting/qoutlinemapper.cpp +++ b/src/gui/painting/qoutlinemapper.cpp @@ -47,6 +47,8 @@ QT_BEGIN_NAMESPACE +static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + #define qreal_to_fixed_26_6(f) (int(f * 64)) @@ -214,6 +216,13 @@ void QOutlineMapper::endOutline() elements = m_elements_dev.data(); } + if (m_round_coords) { + // round coordinates to match outlines drawn with drawLine_midpoint_i + for (int i = 0; i < m_elements.size(); ++i) + elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta), + qFloor(elements[i].y() + aliasedCoordinateDelta)); + } + controlPointRect = boundingRect(elements, element_count); #ifdef QT_DEBUG_CONVERT diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h index 4dd28ac..0f2303c 100644 --- a/src/gui/painting/qoutlinemapper_p.h +++ b/src/gui/painting/qoutlinemapper_p.h @@ -95,7 +95,8 @@ public: m_tags(0), m_contours(0), m_polygon_dev(0), - m_in_clip_elements(false) + m_in_clip_elements(false), + m_round_coords(false) { } @@ -201,6 +202,8 @@ public: QT_FT_Outline *convertPath(const QPainterPath &path); QT_FT_Outline *convertPath(const QVectorPath &path); + void setCoordinateRounding(bool coordinateRounding) { m_round_coords = coordinateRounding; } + inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? 0 : m_element_types.data(); } public: @@ -234,6 +237,9 @@ public: bool m_valid; bool m_in_clip_elements; + +private: + bool m_round_coords; }; QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 4f8af48..b730be3 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -127,6 +127,9 @@ void dumpClip(int width, int height, const QClipData *clip); // 4 pixels. #define int_dim(pos, dim) (int(pos+dim) - int(pos)) +// use the same rounding as in qrasterizer.cpp (6 bit fixed point) +static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + #ifdef Q_WS_WIN extern bool qt_cleartype_enabled; #endif @@ -1666,10 +1669,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) static inline QRect toNormalizedFillRect(const QRectF &rect) { - int x1 = qRound(rect.x()); - int y1 = qRound(rect.y()); - int x2 = qRound(rect.right()); - int y2 = qRound(rect.bottom()); + int x1 = qRound(rect.x() + aliasedCoordinateDelta); + int y1 = qRound(rect.y() + aliasedCoordinateDelta); + int x2 = qRound(rect.right() + aliasedCoordinateDelta); + int y2 = qRound(rect.bottom() + aliasedCoordinateDelta); if (x2 < x1) qSwap(x1, x2); @@ -1939,7 +1942,9 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly // Do the fill... ensureBrush(); if (s->brushData.blend) { + d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque()); fillPolygon(points, pointCount, mode); + d->outlineMapper->setCoordinateRounding(false); } } @@ -1986,6 +1991,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg if (s->brushData.blend) { // Compose polygon fill.., ensureOutlineMapper(); + d->outlineMapper->setCoordinateRounding(s->penData.blend != 0); d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill); d->outlineMapper->moveTo(*points); const QPoint *p = points; @@ -1999,6 +2005,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect, &s->brushData); d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data()); + d->outlineMapper->setCoordinateRounding(false); } } @@ -2255,7 +2262,10 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe int sr_b = qCeil(sr.bottom()) - 1; if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) { + // as fillRect will apply the aliased coordinate delta we need to + // subtract it here as we don't use it for image drawing QTransform old = s->matrix; + s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta); // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied. QRgb color = img.pixel(sr_l, sr_t); @@ -2399,9 +2409,11 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe d->initializeRasterizer(&d->image_filler_xform); d->rasterizer->setAntialiased(s->flags.antialiased); + const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta); + const QRectF &rect = r.normalized(); - const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f); - const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f); + const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs; + const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs; if (s->flags.tx_noshear) d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width()); @@ -2410,12 +2422,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } #endif + const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta; QPainterPath path; path.addRect(r); QTransform m = s->matrix; s->matrix = QTransform(m.m11(), m.m12(), m.m13(), m.m21(), m.m22(), m.m23(), - m.m31(), m.m32(), m.m33()); + m.m31() - offs, m.m32() - offs, m.m33()); fillPath(path, &d->image_filler_xform); s->matrix = m; } else { @@ -2867,6 +2880,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, rightShift = 3; // divide by 8 int margin = cache->glyphMargin(); + const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); for (int i=0; isetFontScale(matrix.m11()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta); for (int i=0; igetCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize); - const int x = qFloor(positions[i].x + tmetrics.HorizBearingX()); - const int y = qFloor(positions[i].y - tmetrics.HorizBearingY()); + const int x = qFloor(positions[i].x + metrics.x + aliasDelta); + const int y = qFloor(positions[i].y + metrics.y + aliasDelta); alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight); } @@ -3125,7 +3140,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte || (fontEngine->type() == QFontEngine::Proxy && !(static_cast(fontEngine)->drawAsOutline())) )) { - fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti); + fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti); return; } #endif // Q_WS_QWS @@ -3148,6 +3163,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte for(int i = 0; i < glyphs.size(); i++) { QImage img = fontEngine->alphaMapForGlyph(glyphs[i]); glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); + // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here? alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(), qRound(positions[i].x + metrics.x), qRound(positions[i].y + metrics.y), diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index 75116c2..bd38286 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -62,8 +62,8 @@ typedef int Q16Dot16; #define SPAN_BUFFER_SIZE 256 -#define COORD_ROUNDING 0 // 0: round up, 1: round down -#define COORD_OFFSET 0 // 26.6, 32 is half a pixel +#define COORD_ROUNDING 1 // 0: round up, 1: round down +#define COORD_OFFSET 32 // 26.6, 32 is half a pixel static inline QT_FT_Vector PointToVector(const QPointF &p) { -- cgit v0.12 From 457c33d9fd308542c9290fd60bf86960f9251255 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt Date: Thu, 19 May 2011 13:55:12 +0200 Subject: Wayland: send surface id + process id pairs to compositor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables doing window/process management since we can now actually map the process we've launched to a window. Reviewed-by: Samuel Rødal --- src/plugins/platforms/wayland/qwaylanddisplay.cpp | 15 ++++ src/plugins/platforms/wayland/qwaylanddisplay.h | 11 +++ src/plugins/platforms/wayland/qwaylandwindow.cpp | 10 ++- src/plugins/platforms/wayland/wayland.pro | 2 + .../qwaylandwindowmanager-client-protocol.h | 82 +++++++++++++++++++++ .../qwaylandwindowmanagerintegration.cpp | 84 ++++++++++++++++++++++ .../qwaylandwindowmanagerintegration.h | 69 ++++++++++++++++++ .../wayland-windowmanager-protocol.c | 36 ++++++++++ .../windowmanager_integration.pri | 16 +++++ 9 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h create mode 100644 src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp create mode 100644 src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h create mode 100644 src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c create mode 100644 src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 876b46a..dcfaf0f 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -50,6 +50,10 @@ #include "gl_integration/qwaylandglintegration.h" #endif +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT +#include "windowmanager_integration/qwaylandwindowmanagerintegration.h" +#endif + #include #include @@ -95,6 +99,13 @@ QWaylandGLIntegration * QWaylandDisplay::eglIntegration() } #endif +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT +QWaylandWindowManagerIntegration *QWaylandDisplay::windowManagerIntegration() +{ + return mWindowManagerIntegration; +} +#endif + void QWaylandDisplay::shellHandleConfigure(void *data, struct wl_shell *shell, uint32_t time, uint32_t edges, struct wl_surface *surface, @@ -134,6 +145,10 @@ QWaylandDisplay::QWaylandDisplay(void) mEglIntegration->initialize(); #endif +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT + mWindowManagerIntegration = QWaylandWindowManagerIntegration::createIntegration(this); +#endif + connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(flushRequests())); mFd = wl_display_get_fd(mDisplay, sourceUpdate, this); diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h index a2cb1b2..81deb3d 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay.h @@ -55,6 +55,8 @@ class QWaylandBuffer; class QPlatformScreen; class QWaylandScreen; class QWaylandGLIntegration; +class QWaylandWindowManagerIntegration; + class QWaylandDisplay : public QObject { Q_OBJECT @@ -74,6 +76,11 @@ public: #ifdef QT_WAYLAND_GL_SUPPORT QWaylandGLIntegration *eglIntegration(); #endif + +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT + QWaylandWindowManagerIntegration *windowManagerIntegration(); +#endif + void setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y); void syncCallback(wl_display_sync_func_t func, void *data); @@ -123,6 +130,10 @@ private: QWaylandGLIntegration *mEglIntegration; #endif +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT + QWaylandWindowManagerIntegration *mWindowManagerIntegration; +#endif + static void shellHandleConfigure(void *data, struct wl_shell *shell, uint32_t time, uint32_t edges, struct wl_surface *surface, diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 53f2f48..d2a7647 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -46,6 +46,11 @@ #include "qwaylandinputdevice.h" #include "qwaylandscreen.h" +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT +#include "windowmanager_integration/qwaylandwindowmanagerintegration.h" +#endif + +#include #include #include @@ -60,6 +65,10 @@ QWaylandWindow::QWaylandWindow(QWidget *window) static WId id = 1; mWindowId = id++; +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT + mDisplay->windowManagerIntegration()->mapClientToProcess(qApp->applicationPid()); +#endif + mSurface = mDisplay->createSurface(this); } @@ -120,7 +129,6 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer) } } - void QWaylandWindow::damage(const QRegion ®ion) { //We have to do sync stuff before calling damage, or we might diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index 8d2d4b5..d2498b2 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -34,8 +34,10 @@ QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_WAYLAND INCLUDEPATH += $$PWD include ($$PWD/gl_integration/gl_integration.pri) +include ($$PWD/windowmanager_integration/windowmanager_integration.pri) include (../fontdatabases/genericunix/genericunix.pri) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target + diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h new file mode 100644 index 0000000..ec776c5 --- /dev/null +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2010 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + +#ifndef WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H +#define WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-util.h" + +struct wl_client; + +struct wl_windowmanager; + +extern const struct wl_interface wl_windowmanager_interface; + +#define WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0 + +static inline struct wl_windowmanager * +wl_windowmanager_create(struct wl_display *display, uint32_t id, uint32_t /*version*/) +{ + // ### does not run without latest wayland. must be enabled later + //wl_display_bind(display, id, "wl_windowmanager", version); + + return (struct wl_windowmanager *) + wl_proxy_create_for_id(display, &wl_windowmanager_interface, id); +} + +static inline void +wl_windowmanager_set_user_data(struct wl_windowmanager *wl_windowmanager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_windowmanager, user_data); +} + +static inline void * +wl_windowmanager_get_user_data(struct wl_windowmanager *wl_windowmanager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_windowmanager); +} + +static inline void +wl_windowmanager_destroy(struct wl_windowmanager *wl_windowmanager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_windowmanager); +} + +static inline void +wl_windowmanager_map_client_to_process(struct wl_windowmanager *wl_windowmanager, uint32_t processid) +{ + wl_proxy_marshal((struct wl_proxy *) wl_windowmanager, + WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp new file mode 100644 index 0000000..8a8e5a9 --- /dev/null +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandwindowmanagerintegration.h" +#include "qwaylandwindowmanager-client-protocol.h" + +#include + +QWaylandWindowManagerIntegration *QWaylandWindowManagerIntegration::createIntegration(QWaylandDisplay *waylandDisplay) +{ + return new QWaylandWindowManagerIntegration(waylandDisplay); +} + +QWaylandWindowManagerIntegration::QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay) + : mWaylandDisplay(waylandDisplay) + , mWaylandWindowManager(0) +{ + wl_display_add_global_listener(mWaylandDisplay->wl_display(), + QWaylandWindowManagerIntegration::wlHandleListenerGlobal, + this); +} + +QWaylandWindowManagerIntegration::~QWaylandWindowManagerIntegration() +{ + +} + +struct wl_windowmanager *QWaylandWindowManagerIntegration::windowManager() const +{ + return mWaylandWindowManager; +} + +void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(wl_display *display, uint32_t id, const char *interface, + uint32_t version, void *data) +{ + if (strcmp(interface, "wl_windowmanager") == 0) { + QWaylandWindowManagerIntegration *integration = static_cast(data); + integration->mWaylandWindowManager = wl_windowmanager_create(display,id, version); + } +} + +void QWaylandWindowManagerIntegration::mapClientToProcess(long long processId) +{ + wl_windowmanager_map_client_to_process(mWaylandWindowManager, (uint32_t) processId); +} + diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h new file mode 100644 index 0000000..01a7bdd --- /dev/null +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDWINDOWMANAGERINTEGRATION_H +#define QWAYLANDWINDOWMANAGERINTEGRATION_H + +#include +#include "wayland-client.h" +#include "qwaylanddisplay.h" + +class QWaylandWindowManagerIntegration +{ +public: + explicit QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay); + virtual ~QWaylandWindowManagerIntegration(); + static QWaylandWindowManagerIntegration *createIntegration(QWaylandDisplay *waylandDisplay); + struct wl_windowmanager *windowManager() const; + + void mapSurfaceToProcess(struct wl_surface *surface, long long processId); + void mapClientToProcess(long long processId); + +private: + static void wlHandleListenerGlobal(wl_display *display, uint32_t id, + const char *interface, uint32_t version, void *data); + +private: + QWaylandDisplay *mWaylandDisplay; + struct wl_windowmanager *mWaylandWindowManager; +}; + +#endif // QWAYLANDWINDOWMANAGERINTEGRATION_H diff --git a/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c b/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c new file mode 100644 index 0000000..48049d8 --- /dev/null +++ b/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2010 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + +#include +#include +#include "wayland-util.h" + +static const struct wl_message wl_windowmanager_requests[] = { + { "map_client_to_process", "u", NULL }, +}; + +WL_EXPORT const struct wl_interface wl_windowmanager_interface = { + "wl_windowmanager", 1, + ARRAY_LENGTH(wl_windowmanager_requests), wl_windowmanager_requests, + 0, NULL, +}; diff --git a/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri new file mode 100644 index 0000000..a282182 --- /dev/null +++ b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri @@ -0,0 +1,16 @@ +DEFINES += QT_WAYLAND_WINDOWMANAGER_SUPPORT + +contains(DEFINES, QT_WAYLAND_WINDOWMANAGER_SUPPORT) { + + HEADERS += \ + $$PWD/qwaylandwindowmanager-client-protocol.h \ + $$PWD/qwaylandwindowmanagerintegration.h + + SOURCES += \ + $$PWD/qwaylandwindowmanagerintegration.cpp \ + $$PWD/wayland-windowmanager-protocol.c + +} + + + -- cgit v0.12 From 14bf7c3761efe208ce19047b8ddc3f811a63a437 Mon Sep 17 00:00:00 2001 From: aavit Date: Thu, 19 May 2011 12:48:35 +0200 Subject: Revert "fix breakages in qpainter autotests." This reverts commit 50a53d2f7a7e12cd597dc72a08ad62b79fee4554. ...which was required because of 69fc9e594e6d5da87bff42707973683f84b67c93 "Fix how subpixel positions are intepreted in an aliased grid." which was reverted in f8e85838c5531b56c2175cbdb9c24db426f7fd89 because of 37c329a3e35fabc88fbcad824a69f37c671d2132 "New algorithm for drawing thin lines". phew! --- tests/auto/qpainter/tst_qpainter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index 9844434..65ac2f9 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -1315,7 +1315,7 @@ void tst_QPainter::drawRect2() p.end(); QRect stroke = getPaintedSize(image, Qt::white); - QCOMPARE(stroke, fill.adjusted(0, 0, 1, 1)); + QCOMPARE(stroke.adjusted(1, 1, 0, 0), fill.adjusted(0, 0, 1, 1)); } } @@ -1412,13 +1412,13 @@ void tst_QPainter::drawPath_data() { QPainterPath p; p.addRect(2.25, 2.25, 10, 10); - QTest::newRow("non-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10; + QTest::newRow("non-aligned rect") << p << QRect(3, 3, 10, 10) << 10 * 10; } { QPainterPath p; p.addRect(2.25, 2.25, 10.5, 10.5); - QTest::newRow("non-aligned rect 2") << p << QRect(2, 2, 11, 11) << 11 * 11; + QTest::newRow("non-aligned rect 2") << p << QRect(3, 3, 10, 10) << 10 * 10; } { -- cgit v0.12 From 7cfd06ee22a875d7658ce6668b418e6f8c6f6480 Mon Sep 17 00:00:00 2001 From: aavit Date: Thu, 19 May 2011 16:05:02 +0200 Subject: Compilation fix of f8e8583 --- src/gui/painting/qpaintengine_raster.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index b730be3..7dda940 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2928,6 +2928,7 @@ void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti) if (matrix.type() == QTransform::TxScale) fe->setFontScale(matrix.m11()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta); for (int i=0; igetCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize); - const int x = qFloor(positions[i].x + metrics.x + aliasDelta); - const int y = qFloor(positions[i].y + metrics.y + aliasDelta); + const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta); + const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta); alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight); } -- cgit v0.12 From aea5e35f57d061b133d2fa613d10f5e0118f5706 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt Date: Thu, 19 May 2011 16:30:44 +0200 Subject: Don't crash if windowmanager is not initialized This can happen if there is e.g. no wayland server. Reviewed-by: sroedal --- .../windowmanager_integration/qwaylandwindowmanagerintegration.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp index 8a8e5a9..b93e6d2 100644 --- a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp @@ -79,6 +79,7 @@ void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(wl_display *displa void QWaylandWindowManagerIntegration::mapClientToProcess(long long processId) { - wl_windowmanager_map_client_to_process(mWaylandWindowManager, (uint32_t) processId); + if (mWaylandWindowManager) + wl_windowmanager_map_client_to_process(mWaylandWindowManager, (uint32_t) processId); } -- cgit v0.12 From 4af11f2c6666c55657569f946c33816f33711225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 19 May 2011 14:58:18 +0200 Subject: Compile fixes for Xlib plugin. --- src/plugins/platforms/xlib/qxlibscreen.cpp | 6 +++--- src/plugins/platforms/xlib/qxlibstatic.cpp | 4 ---- src/plugins/platforms/xlib/qxlibstatic.h | 1 + src/plugins/platforms/xlib/qxlibwindow.cpp | 17 +++++++++-------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/platforms/xlib/qxlibscreen.cpp b/src/plugins/platforms/xlib/qxlibscreen.cpp index 7c8a367..920116a 100644 --- a/src/plugins/platforms/xlib/qxlibscreen.cpp +++ b/src/plugins/platforms/xlib/qxlibscreen.cpp @@ -41,6 +41,8 @@ #include "qxlibscreen.h" +#include + #include "qxlibcursor.h" #include "qxlibwindow.h" #include "qxlibkeyboard.h" @@ -54,8 +56,6 @@ #include -#include - QT_BEGIN_NAMESPACE static int (*original_x_errhandler)(Display *dpy, XErrorEvent *); @@ -201,7 +201,7 @@ QXlibScreen::QXlibScreen() #ifndef DONT_USE_MIT_SHM - Status MIT_SHM_extension_supported = XShmQueryExtension (mDisplay->nativeDisplay()); + int MIT_SHM_extension_supported = XShmQueryExtension (mDisplay->nativeDisplay()); Q_ASSERT(MIT_SHM_extension_supported == True); #endif original_x_errhandler = XSetErrorHandler(qt_x_errhandler); diff --git a/src/plugins/platforms/xlib/qxlibstatic.cpp b/src/plugins/platforms/xlib/qxlibstatic.cpp index 6117781..7b562ea 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.cpp +++ b/src/plugins/platforms/xlib/qxlibstatic.cpp @@ -51,10 +51,6 @@ #include -#ifndef QT_NO_XFIXES -#include -#endif // QT_NO_XFIXES - static const char * x11_atomnames = { // window-manager <-> client protocols "WM_PROTOCOLS\0" diff --git a/src/plugins/platforms/xlib/qxlibstatic.h b/src/plugins/platforms/xlib/qxlibstatic.h index 72cfaec..7d1a0d0 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.h +++ b/src/plugins/platforms/xlib/qxlibstatic.h @@ -132,6 +132,7 @@ typedef char *XPointer; #endif #ifndef QT_NO_XFIXES +#include typedef Bool (*PtrXFixesQueryExtension)(Display *, int *, int *); typedef Status (*PtrXFixesQueryVersion)(Display *, int *, int *); typedef void (*PtrXFixesSetCursorName)(Display *dpy, Cursor cursor, const char *name); diff --git a/src/plugins/platforms/xlib/qxlibwindow.cpp b/src/plugins/platforms/xlib/qxlibwindow.cpp index 9a05fc6..90bcc0d 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.cpp +++ b/src/plugins/platforms/xlib/qxlibwindow.cpp @@ -47,14 +47,6 @@ #include "qxlibstatic.h" #include "qxlibdisplay.h" -#include -#include -#include -#include - -#include -#include - #if !defined(QT_NO_OPENGL) #if !defined(QT_OPENGL_ES_2) #include "qglxintegration.h" @@ -66,6 +58,15 @@ #endif //QT_OPENGL_ES_2 #endif //QT_NO_OPENGL + +#include +#include +#include +#include + +#include +#include + //#define MYX11_DEBUG QT_BEGIN_NAMESPACE -- cgit v0.12 From c15b41056e60abdbb4d835e27a360f01be618a4f Mon Sep 17 00:00:00 2001 From: Janusz Lewandowski Date: Thu, 19 May 2011 16:21:39 +0200 Subject: Lighthouse minimal: Add support for transparency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge-request: 1231 Reviewed-by: Samuel Rødal --- src/plugins/platforms/minimal/qminimalintegration.cpp | 4 ++-- src/plugins/platforms/minimal/qminimalintegration.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 3a545e4..44a4eb6 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -50,8 +50,8 @@ QMinimalIntegration::QMinimalIntegration() QMinimalScreen *mPrimaryScreen = new QMinimalScreen(); mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320); - mPrimaryScreen->mDepth = 16; - mPrimaryScreen->mFormat = QImage::Format_RGB16; + mPrimaryScreen->mDepth = 32; + mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied; mScreens.append(mPrimaryScreen); } diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h index 5f93443..993d364 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.h +++ b/src/plugins/platforms/minimal/qminimalintegration.h @@ -51,7 +51,7 @@ class QMinimalScreen : public QPlatformScreen { public: QMinimalScreen() - : mDepth(16), mFormat(QImage::Format_RGB16) {} + : mDepth(32), mFormat(QImage::Format_ARGB32_Premultiplied) {} QRect geometry() const { return mGeometry; } int depth() const { return mDepth; } -- cgit v0.12 From a3b627e1c5ce03a2500ab35c64729b1995639dcc Mon Sep 17 00:00:00 2001 From: Janusz Lewandowski Date: Thu, 19 May 2011 16:21:40 +0200 Subject: Lighthouse xcb and xlib: Add support for transparency of GLX windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge-request: 1231 Reviewed-by: Samuel Rødal --- .../platforms/glxconvenience/glxconvenience.pri | 8 ++++++ .../platforms/glxconvenience/qglxconvenience.cpp | 30 ++++++++++++++++------ .../qwaylandxcompositeglxcontext.cpp | 4 ++- src/plugins/platforms/xcb/qxcbwindow.cpp | 8 +++++- src/plugins/platforms/xcb/qxcbwindow.h | 6 +++++ src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 11 ++++---- src/plugins/platforms/xlib/qxlibintegration.cpp | 2 +- src/plugins/platforms/xlib/qxlibwindow.cpp | 13 ++++++++-- src/plugins/platforms/xlib/qxlibwindow.h | 8 ++++++ src/plugins/platforms/xlib/qxlibwindowsurface.cpp | 13 +++++----- 10 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/plugins/platforms/glxconvenience/glxconvenience.pri b/src/plugins/platforms/glxconvenience/glxconvenience.pri index d6c9922..b4d43a3 100644 --- a/src/plugins/platforms/glxconvenience/glxconvenience.pri +++ b/src/plugins/platforms/glxconvenience/glxconvenience.pri @@ -5,3 +5,11 @@ HEADERS += \ SOURCES += \ $$PWD/qglxconvenience.cpp + +CONFIG += xrender + +xrender { + LIBS += -lXrender +} else { + DEFINES += QT_NO_XRENDER +} diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp index 7cee3e2..eb0f6a6 100644 --- a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp +++ b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp @@ -43,6 +43,10 @@ #include +#ifndef QT_NO_XRENDER +#include +#endif + enum { XFocusOut = FocusOut, XFocusIn = FocusIn, @@ -84,14 +88,15 @@ QVector qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit spec[i++] = GLX_ALPHA_SIZE; spec[i++] = (format.alphaBufferSize() == -1) ? 1 : format.alphaBufferSize(); } - spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + if (format.accum()) { + spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - if (format.alpha()) { - spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + if (format.alpha()) { + spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); + } } - } else { spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_COLOR_INDEX_BIT; //I'm really not sure if this works.... spec[i++] = GLX_BUFFER_SIZE; spec[i++] = 8; @@ -136,8 +141,17 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , const QPlatformWindow if (reducedFormat.alpha()) { int alphaSize; glXGetFBConfigAttrib(display,configs[i],GLX_ALPHA_SIZE,&alphaSize); - if (alphaSize > 0) - break; + if (alphaSize > 0) { + XVisualInfo *visual = glXGetVisualFromFBConfig(display, chosenConfig); +#if !defined(QT_NO_XRENDER) + XRenderPictFormat *pictFormat = XRenderFindVisualFormat(display, visual->visual); + if (pictFormat->direct.alphaMask > 0) + break; +#else + if (visual->depth == 32) + break; +#endif + } } else { break; // Just choose the first in the list if there's no alpha requested } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp index caf5117..baf0fa3 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp @@ -132,10 +132,12 @@ void QWaylandXCompositeGLXContext::geometryChanged() Colormap cmap = XCreateColormap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),visualInfo->visual,AllocNone); XSetWindowAttributes a; + a.background_pixel = WhitePixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); + a.border_pixel = BlackPixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); a.colormap = cmap; mXWindow = XCreateWindow(mGlxIntegration->xDisplay(), mGlxIntegration->rootWindow(),0, 0, size.width(), size.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); + CWBackPixel|CWBorderPixel|CWColormap, &a); XCompositeRedirectWindow(mGlxIntegration->xDisplay(), mXWindow, CompositeRedirectManual); XMapWindow(mGlxIntegration->xDisplay(), mXWindow); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0456638..3365c22 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -131,13 +131,17 @@ QXcbWindow::QXcbWindow(QWidget *tlw) visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount); #endif //XCB_USE_GLX if (visualInfo) { + m_depth = visualInfo->depth; + m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone); XSetWindowAttributes a; + a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); + a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.colormap = cmap; m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); + CWBackPixel|CWBorderPixel|CWColormap, &a); printf("created GL window: %d\n", m_window); } else { @@ -147,6 +151,8 @@ QXcbWindow::QXcbWindow(QWidget *tlw) #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL) { m_window = xcb_generate_id(xcb_connection()); + m_depth = m_screen->screen()->root_depth; + m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index e049837..20b4640 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -74,6 +75,8 @@ public: QPlatformGLContext *glContext() const; xcb_window_t window() const { return m_window; } + uint depth() const { return m_depth; } + QImage::Format format() const { return m_format; } void handleExposeEvent(const xcb_expose_event_t *event); void handleClientMessageEvent(const xcb_client_message_event_t *event); @@ -99,6 +102,9 @@ private: xcb_window_t m_window; QPlatformGLContext *m_context; + uint m_depth; + QImage::Format m_format; + xcb_sync_int64_t m_syncValue; xcb_sync_counter_t m_syncCounter; diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index 718f093..38c01f9 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -58,7 +58,7 @@ class QXcbShmImage : public QXcbObject { public: - QXcbShmImage(QXcbScreen *connection, const QSize &size); + QXcbShmImage(QXcbScreen *connection, const QSize &size, uint depth, QImage::Format format); ~QXcbShmImage() { destroy(); } QImage *image() { return &m_qimage; } @@ -81,7 +81,7 @@ private: QRegion m_dirty; }; -QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) +QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) : QXcbObject(screen->connection()) , m_gc(0) , m_gc_window(0) @@ -91,7 +91,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) size.width(), size.height(), XCB_IMAGE_FORMAT_Z_PIXMAP, - screen->depth(), + depth, 0, ~0, 0); @@ -111,7 +111,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size) if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed"; - m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, screen->format()); + m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); } void QXcbShmImage::destroy() @@ -232,9 +232,10 @@ void QXcbWindowSurface::resize(const QSize &size) QWindowSurface::resize(size); QXcbScreen *screen = static_cast(QPlatformScreen::platformScreenForWidget(window())); + QXcbWindow* win = static_cast(window()->platformWindow()); delete m_image; - m_image = new QXcbShmImage(screen, size); + m_image = new QXcbShmImage(screen, size, win->depth(), win->format()); Q_XCB_NOOP(connection()); m_syncingResize = true; diff --git a/src/plugins/platforms/xlib/qxlibintegration.cpp b/src/plugins/platforms/xlib/qxlibintegration.cpp index 78f907a..b0c8bc9 100644 --- a/src/plugins/platforms/xlib/qxlibintegration.cpp +++ b/src/plugins/platforms/xlib/qxlibintegration.cpp @@ -150,7 +150,7 @@ bool QXlibIntegration::hasOpenGL() const { #if !defined(QT_NO_OPENGL) #if !defined(QT_OPENGL_ES_2) - QXlibScreen *screen = static_cast(mScreens.at(0)); + QXlibScreen *screen = static_cast(mScreens.at(0)); return glXQueryExtension(screen->display()->nativeDisplay(), 0, 0) != 0; #else static bool eglHasbeenInitialized = false; diff --git a/src/plugins/platforms/xlib/qxlibwindow.cpp b/src/plugins/platforms/xlib/qxlibwindow.cpp index 90bcc0d..4efcb11 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.cpp +++ b/src/plugins/platforms/xlib/qxlibwindow.cpp @@ -102,18 +102,27 @@ QXlibWindow::QXlibWindow(QWidget *window) visualInfo = XGetVisualInfo(mScreen->display()->nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount); #endif //!defined(QT_OPENGL_ES_2) if (visualInfo) { - Colormap cmap = XCreateColormap(mScreen->display()->nativeDisplay(),mScreen->rootWindow(),visualInfo->visual,AllocNone); + mDepth = visualInfo->depth; + mFormat = (mDepth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + mVisual = visualInfo->visual; + Colormap cmap = XCreateColormap(mScreen->display()->nativeDisplay(), mScreen->rootWindow(), visualInfo->visual, AllocNone); XSetWindowAttributes a; + a.background_pixel = WhitePixel(mScreen->display()->nativeDisplay(), mScreen->xScreenNumber()); + a.border_pixel = BlackPixel(mScreen->display()->nativeDisplay(), mScreen->xScreenNumber()); a.colormap = cmap; x_window = XCreateWindow(mScreen->display()->nativeDisplay(), mScreen->rootWindow(),x, y, w, h, 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); + CWBackPixel|CWBorderPixel|CWColormap, &a); } else { qFatal("no window!"); } #endif //!defined(QT_NO_OPENGL) } else { + mDepth = mScreen->depth(); + mFormat = (mDepth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + mVisual = mScreen->defaultVisual(); + x_window = XCreateSimpleWindow(mScreen->display()->nativeDisplay(), mScreen->rootWindow(), x, y, w, h, 0 /*border_width*/, mScreen->blackPixel(), mScreen->whitePixel()); diff --git a/src/plugins/platforms/xlib/qxlibwindow.h b/src/plugins/platforms/xlib/qxlibwindow.h index 08694a5..2d11224 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.h +++ b/src/plugins/platforms/xlib/qxlibwindow.h @@ -122,6 +122,10 @@ public: Window xWindow() const; GC graphicsContext() const; + inline uint depth() const { return mDepth; } + QImage::Format format() const { return mFormat; } + Visual* visual() const { return mVisual; } + protected: QVector getNetWmState() const; void setMWMHints(const QXlibMWMHints &mwmhints); @@ -135,6 +139,10 @@ private: Window x_window; GC gc; + uint mDepth; + QImage::Format mFormat; + Visual* mVisual; + GC createGC(); QPlatformGLContext *mGLContext; diff --git a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp index 513f10d..78fe387 100644 --- a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp +++ b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp @@ -80,20 +80,19 @@ void QXlibShmImageInfo::destroy() void QXlibWindowSurface::resizeShmImage(int width, int height) { + QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window()); + QXlibWindow *win = static_cast(window()->platformWindow()); #ifdef DONT_USE_MIT_SHM - shm_img = QImage(width, height, QImage::Format_RGB32); + shm_img = QImage(width, height, win->format()); #else - QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window()); if (image_info) image_info->destroy(); else image_info = new QXlibShmImageInfo(screen->display()->nativeDisplay()); - Visual *visual = screen->defaultVisual(); - - XImage *image = XShmCreateImage (screen->display()->nativeDisplay(), visual, 24, ZPixmap, 0, + XImage *image = XShmCreateImage (screen->display()->nativeDisplay(), win->visual(), win->depth(), ZPixmap, 0, &image_info->shminfo, width, height); @@ -160,11 +159,11 @@ void QXlibWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPo #ifdef DONT_USE_MIT_SHM // just convert the image every time... if (!shm_img.isNull()) { - Visual *visual = DefaultVisual(screen->display(), screen->xScreenNumber()); + QXlibWindow *win = static_cast(window()->platformWindow()); QImage image = shm_img; //img.convertToFormat( - XImage *xi = XCreateImage(screen->display(), visual, 24, ZPixmap, + XImage *xi = XCreateImage(screen->display(), win->visual(), win->depth(), ZPixmap, 0, (char *) image.scanLine(0), image.width(), image.height(), 32, image.bytesPerLine()); -- cgit v0.12 From 6241e39cff9311c943430ff2f31236b13618f2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 19 May 2011 16:18:21 +0200 Subject: Full translucent background support in xcb and xlib backend. Make sure to pick an alpha visual also for non-GL surface types, and to ask for alpha in the window format if the WA_TranslucentBackground attribute is set. Reviewed-by: Janusz Lewandowski --- src/gui/kernel/qwidget_qpa.cpp | 11 +++++++++-- src/opengl/qgl_qpa.cpp | 2 ++ src/opengl/qwindowsurface_gl.cpp | 18 +++++++++++++----- src/plugins/platforms/xcb/qxcbwindow.cpp | 3 ++- src/plugins/platforms/xcb/qxcbwindowsurface.cpp | 11 +++++++++++ src/plugins/platforms/xlib/qxlibwindow.cpp | 8 +++++--- src/plugins/platforms/xlib/qxlibwindowsurface.cpp | 14 +++++++++++++- 7 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/gui/kernel/qwidget_qpa.cpp b/src/gui/kernel/qwidget_qpa.cpp index 001810e..960073c 100644 --- a/src/gui/kernel/qwidget_qpa.cpp +++ b/src/gui/kernel/qwidget_qpa.cpp @@ -731,12 +731,19 @@ QPlatformWindowFormat QWidget::platformWindowFormat() const { Q_D(const QWidget); + QPlatformWindowFormat format; + QTLWExtra *extra = d->maybeTopData(); if (extra){ - return extra->platformWindowFormat; + format = extra->platformWindowFormat; } else { - return QPlatformWindowFormat::defaultFormat(); + format = QPlatformWindowFormat::defaultFormat(); } + + if (testAttribute(Qt::WA_TranslucentBackground)) + format.setAlpha(true); + + return format; } void QWidgetPrivate::createSysExtra() diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp index 994344c..9da650f 100644 --- a/src/opengl/qgl_qpa.cpp +++ b/src/opengl/qgl_qpa.cpp @@ -150,6 +150,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (shareContext) { winFormat.setSharedContext(shareContext->d_func()->platformContext); } + if (widget->testAttribute(Qt::WA_TranslucentBackground)) + winFormat.setAlpha(true); winFormat.setWindowApi(QPlatformWindowFormat::OpenGL); winFormat.setWindowSurface(false); widget->setPlatformWindowFormat(winFormat); diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index 49b3dc2..ff57446 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -542,19 +542,27 @@ void QGLWindowSurface::beginPaint(const QRegion &) d_ptr->did_paint = true; updateGeometry(); - if (!context()) - return; - int clearFlags = 0; - if (context()->d_func()->workaround_needsFullClearOnEveryFrame) + QGLContext *ctx = reinterpret_cast(window()->d_func()->extraData()->glContext); + + if (!ctx) + return; + + if (ctx->d_func()->workaround_needsFullClearOnEveryFrame) clearFlags = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - else if (context()->format().alpha()) + else if (ctx->format().alpha()) clearFlags = GL_COLOR_BUFFER_BIT; if (clearFlags) { + if (d_ptr->fbo) + d_ptr->fbo->bind(); + glClearColor(0.0, 0.0, 0.0, 0.0); glClear(clearFlags); + + if (d_ptr->fbo) + d_ptr->fbo->release(); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3365c22..0dd29eb 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -113,7 +113,8 @@ QXcbWindow::QXcbWindow(QWidget *tlw) #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) + || tlw->platformWindowFormat().alpha()) { #if defined(XCB_USE_GLX) XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index 38c01f9..88a54dc 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -54,6 +54,7 @@ #include #include +#include class QXcbShmImage : public QXcbObject { @@ -189,6 +190,16 @@ QPaintDevice *QXcbWindowSurface::paintDevice() void QXcbWindowSurface::beginPaint(const QRegion ®ion) { m_image->preparePaint(region); + + if (m_image->image()->hasAlphaChannel()) { + QPainter p(m_image->image()); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector rects = region.rects(); + const QColor blank = Qt::transparent; + for (QVector::const_iterator it = rects.begin(); it != rects.end(); ++it) { + p.fillRect(*it, blank); + } + } } void QXcbWindowSurface::endPaint(const QRegion &) diff --git a/src/plugins/platforms/xlib/qxlibwindow.cpp b/src/plugins/platforms/xlib/qxlibwindow.cpp index 4efcb11..50ea7b5 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.cpp +++ b/src/plugins/platforms/xlib/qxlibwindow.cpp @@ -81,9 +81,10 @@ QXlibWindow::QXlibWindow(QWidget *window) int w = window->width(); int h = window->height(); - if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) ) { #if !defined(QT_NO_OPENGL) + if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL + && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) + || window->platformWindowFormat().alpha()) { #if !defined(QT_OPENGL_ES_2) XVisualInfo *visualInfo = qglx_findVisualInfo(mScreen->display()->nativeDisplay(),mScreen->xScreenNumber(),window->platformWindowFormat()); #else @@ -117,8 +118,9 @@ QXlibWindow::QXlibWindow(QWidget *window) } else { qFatal("no window!"); } + } else #endif //!defined(QT_NO_OPENGL) - } else { + { mDepth = mScreen->depth(); mFormat = (mDepth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; mVisual = mScreen->defaultVisual(); diff --git a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp index 78fe387..a917f45 100644 --- a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp +++ b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp @@ -49,6 +49,8 @@ #include "qxlibscreen.h" #include "qxlibdisplay.h" +#include "qpainter.h" + # include # include # include @@ -108,7 +110,7 @@ void QXlibWindowSurface::resizeShmImage(int width, int height) Q_ASSERT(shm_attach_status == True); - shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, QImage::Format_RGB32 ); + shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, win->format() ); #endif painted = false; } @@ -213,6 +215,16 @@ void QXlibWindowSurface::beginPaint(const QRegion ®ion) { Q_UNUSED(region); resizeBuffer(size()); + + if (shm_img.hasAlphaChannel()) { + QPainter p(&shm_img); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector rects = region.rects(); + const QColor blank = Qt::transparent; + for (QVector::const_iterator it = rects.begin(); it != rects.end(); ++it) { + p.fillRect(*it, blank); + } + } } void QXlibWindowSurface::endPaint(const QRegion ®ion) -- cgit v0.12 From 278cf1f37945050c4a46d5acab0659f3a7546a43 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 20 May 2011 10:26:54 +0200 Subject: Fix ligature offset in multi-line text Reviewed-by: Eskil --- src/gui/text/qtextlayout.cpp | 4 ++-- tests/auto/qtextlayout/tst_qtextlayout.cpp | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 07aeb72..9501c0b 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2559,8 +2559,8 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const } else { bool rtl = eng->isRightToLeft(); bool visual = eng->visualCursorMovement(); + int end = qMin(lineEnd, si->position + l) - si->position; if (reverse) { - int end = qMin(lineEnd, si->position + l) - si->position; int glyph_end = end == l ? si->num_glyphs : logClusters[end]; int glyph_start = glyph_pos; if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem))) @@ -2576,7 +2576,7 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const for (int i = glyph_start; i <= glyph_end; i++) x += glyphs.effectiveAdvance(i); } - x += eng->offsetInLigature(si, pos, line.length, glyph_pos); + x += eng->offsetInLigature(si, pos, end, glyph_pos); } *cursorPos = pos + si->position; diff --git a/tests/auto/qtextlayout/tst_qtextlayout.cpp b/tests/auto/qtextlayout/tst_qtextlayout.cpp index 83c7094..b5712fb 100644 --- a/tests/auto/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/qtextlayout/tst_qtextlayout.cpp @@ -127,6 +127,7 @@ private slots: void textWithSurrogates_qtbug15679(); void textWidthWithStackedTextEngine(); void textWidthWithLineSeparator(); + void cursorInLigatureWithMultipleLines(); private: QFont testFont; @@ -1460,5 +1461,21 @@ void tst_QTextLayout::textWidthWithLineSeparator() QCOMPARE(line1.naturalTextWidth(), line2.naturalTextWidth()); } +void tst_QTextLayout::cursorInLigatureWithMultipleLines() +{ +#if !defined(Q_WS_MAC) + QSKIP("This test can not be run on Mac", SkipAll); +#endif + QTextLayout layout("first line finish", QFont("Times", 20)); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(70); + line = layout.createLine(); + layout.endLayout(); + + // The second line will be "finish", with "fi" as a ligature + QVERIFY(line.cursorToX(0) != line.cursorToX(1)); +} + QTEST_MAIN(tst_QTextLayout) #include "tst_qtextlayout.moc" -- cgit v0.12 From 31e9c098f3c9321eebf1ac3e4c44a2d18d3816b8 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 19 May 2011 23:19:47 +0200 Subject: Fix smaller bugs in the stroker Calculating the continuation point for closed contours was not taking transformations and the half pixel offset into account. --- src/gui/painting/qcosmeticstroker.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index d694b4b..47a1359 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -409,10 +409,11 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal if (clipLine(rx1, ry1, rx2, ry2)) return; - int x1 = toF26Dot6(rx1); - int y1 = toF26Dot6(ry1); - int x2 = toF26Dot6(rx2); - int y2 = toF26Dot6(ry2); + const int half = 32; + int x1 = toF26Dot6(rx1) + half; + int y1 = toF26Dot6(ry1) + half; + int x2 = toF26Dot6(rx2) + half; + int y2 = toF26Dot6(ry2) + half; int dx = qAbs(x2 - x1); int dy = qAbs(y2 - y1); @@ -424,6 +425,7 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal swapped = true; qSwap(y1, y2); qSwap(x1, x2); + --x1; --x2; --y1; --y2; } int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1); int x = x1 << 10; @@ -455,6 +457,7 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal swapped = true; qSwap(x1, x2); qSwap(y1, y2); + --x1; --x2; --y1; --y2; } int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1); int y = y1 << 10; @@ -525,7 +528,9 @@ void QCosmeticStroker::drawPath(const QVectorPath &path) const QPainterPath::ElementType *e = subPath(type, end, points, &closed); if (closed) { const qreal *p = points + 2*(e-type); - calculateLastPoint(p[-4], p[-3], p[-2], p[-1]); + QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix; + QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix; + calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y()); } int caps = (!closed & drawCaps) ? CapBegin : NoCaps; // qDebug() << "closed =" << closed << capString(caps); @@ -577,8 +582,10 @@ void QCosmeticStroker::drawPath(const QVectorPath &path) // handle closed path case bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]); int caps = (!closed & drawCaps) ? CapBegin : NoCaps; - if (closed) - calculateLastPoint(end[-2], end[-1], points[0], points[1]); + if (closed) { + QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix; + calculateLastPoint(p2.x(), p2.y(), p.x(), p.y()); + } points += 2; while (points < end) { -- cgit v0.12 From eedab65056a6898e5a6f6bd103bed53e6787d334 Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Fri, 20 May 2011 12:30:35 +0200 Subject: Fixed inconsistent behaviour in Qt.rect(). The QML function Qt.rect() used to return a null rectangle if the width or height argument were negative. This was inconsistent with Qt.size() and parsing a string of the type "x,y,wxh" which do not check the width and height. Reviewed-by: Samuel --- src/declarative/qml/qdeclarativeengine.cpp | 3 --- tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 9fde18c..1feaeb3 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -1699,9 +1699,6 @@ QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine qsreal w = ctxt->argument(2).toNumber(); qsreal h = ctxt->argument(3).toNumber(); - if (w < 0 || h < 0) - return engine->nullValue(); - return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h))); } diff --git a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp index 80d9d93..518be89 100644 --- a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp +++ b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp @@ -174,7 +174,7 @@ void tst_qdeclarativeqt::rect() QCOMPARE(qvariant_cast(object->property("test2")), QRectF(-10, 13, 100, 109.6)); QCOMPARE(qvariant_cast(object->property("test3")), QRectF()); QCOMPARE(qvariant_cast(object->property("test4")), QRectF()); - QCOMPARE(qvariant_cast(object->property("test5")), QRectF()); + QCOMPARE(qvariant_cast(object->property("test5")), QRectF(10, 13, 100, -109)); delete object; } -- cgit v0.12 From 5651fdf16a22cbf3ccd6663d5d5c95b420a3df13 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Mon, 23 May 2011 11:18:42 +0200 Subject: Force repaint of modal sheet in Cocoa. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the raster engine on Mac OS X, modal sheets only get their content painted once the sliding down animation is over. By forcing the repaint, the modal sheet has the correct painting during the whole animation. Task-number: QTBUG-17426 Reviewed-by: Samuel Rødal --- src/gui/kernel/qapplication_mac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index f607a72..b82d212 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -715,6 +715,7 @@ void qt_event_request_showsheet(QWidget *w) { Q_ASSERT(qt_mac_is_macsheet(w)); #ifdef QT_MAC_USE_COCOA + w->repaint(); [NSApp beginSheet:qt_mac_window_for(w) modalForWindow:qt_mac_window_for(w->parentWidget()) modalDelegate:nil didEndSelector:nil contextInfo:0]; #else -- cgit v0.12 From 5338d78aa9d80ddd2bcb21e6b22cd2cf1522a7d3 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Thu, 19 May 2011 10:29:49 +0200 Subject: Support placing cursor in ligature with mouse or touch We need to find out the closest element in the ligature to the point we clicked (or tapped), currently we do this by dividing the width of that ligature glyph evenly by the number of characters it covered. We only support Common and Greek script at this point, ligatures in other scripts are still handled as a whole. Task-number: QTBUG-19260 Reviewed-by: Eskil --- src/gui/text/qtextengine.cpp | 66 ++++++++++++++++++++++++++++++ src/gui/text/qtextengine_p.h | 2 + src/gui/text/qtextlayout.cpp | 16 ++++---- tests/auto/qtextlayout/tst_qtextlayout.cpp | 25 +++++++++++ 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index ff27bc6..0df543b 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2825,6 +2825,72 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in return 0; } +// Scan in logClusters[from..to-1] for glyph_pos +int QTextEngine::getClusterLength(unsigned short *logClusters, + const HB_CharAttributes *attributes, + int from, int to, int glyph_pos, int *start) +{ + int clusterLength = 0; + for (int i = from; i < to; i++) { + if (logClusters[i] == glyph_pos && attributes[i].charStop) { + if (*start < 0) + *start = i; + clusterLength++; + } + else if (clusterLength) + break; + } + return clusterLength; +} + +int QTextEngine::positionInLigature(const QScriptItem *si, int end, + QFixed x, QFixed edge, int glyph_pos) +{ + unsigned short *logClusters = this->logClusters(si); + int clusterStart = -1; + int clusterLength = 0; + + if (si->analysis.script != QUnicodeTables::Common && + si->analysis.script != QUnicodeTables::Greek) { + if (glyph_pos == -1) + return si->position + end; + else { + int i; + for (i = 0; i < end; i++) + if (logClusters[i] == glyph_pos) + break; + return si->position + i; + } + } + + if (glyph_pos == -1 && end > 0) + glyph_pos = logClusters[end - 1]; + else { + if (x < edge) + glyph_pos--; + } + + const HB_CharAttributes *attrs = attributes(); + clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart); + + if (clusterLength) { + const QGlyphLayout &glyphs = shapedGlyphs(si); + QFixed glyphWidth = glyphs.effectiveAdvance(glyph_pos); + // the approximate width of each individual element of the ligature + QFixed perItemWidth = glyphWidth / clusterLength; + QFixed left = x > edge ? edge : edge - glyphWidth; + int n = ((x - left) / perItemWidth).floor().toInt(); + QFixed dist = x - left - n * perItemWidth; + int closestItem = dist > (perItemWidth / 2) ? n + 1 : n; + int pos = si->position + clusterStart + closestItem; + // Jump to the next charStop + while (!attrs[pos].charStop && pos < end) + pos++; + return pos; + } + return si->position + end; +} + int QTextEngine::previousLogicalPosition(int oldPos) const { const HB_CharAttributes *attrs = attributes(); diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index e06ca1c..8e1d796 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -620,6 +620,7 @@ public: QFixed leadingSpaceWidth(const QScriptLine &line); QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos); + int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos); int previousLogicalPosition(int oldPos) const; int nextLogicalPosition(int oldPos) const; int lineNumberForTextPosition(int pos); @@ -642,6 +643,7 @@ private: void resolveAdditionalFormats() const; int endOfLine(int lineNum); int beginningOfLine(int lineNum); + int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start); }; class QStackTextEngine : public QTextEngine { diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 9501c0b..20edb87 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2691,6 +2691,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const } int glyph_pos = -1; + QFixed edge; // has to be inside run if (cpos == QTextLine::CursorOnCharacter) { if (si.analysis.bidiLevel % 2) { @@ -2701,6 +2702,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (pos < x) break; glyph_pos = gs; + edge = pos; break; } pos -= glyphs.effectiveAdvance(gs); @@ -2713,6 +2715,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (pos > x) break; glyph_pos = gs; + edge = pos; } pos += glyphs.effectiveAdvance(gs); ++gs; @@ -2726,6 +2729,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const while (gs <= ge) { if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { glyph_pos = gs; + edge = pos; dist = qAbs(x-pos); } pos -= glyphs.effectiveAdvance(gs); @@ -2735,6 +2739,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const while (ge >= gs) { if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) { glyph_pos = ge; + edge = pos; dist = qAbs(x-pos); } pos += glyphs.effectiveAdvance(ge); @@ -2746,6 +2751,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const while (gs <= ge) { if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { glyph_pos = gs; + edge = pos; dist = qAbs(x-pos); } pos += glyphs.effectiveAdvance(gs); @@ -2757,6 +2763,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const pos += glyphs.effectiveAdvance(gs); if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { glyph_pos = gs; + edge = pos; dist = qAbs(x-pos); } ++gs; @@ -2773,16 +2780,11 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (rtl && nchars > 0) return insertionPoints[lastLine ? nchars : nchars - 1]; } - return si.position + end; + return eng->positionInLigature(&si, end, x, pos, -1); } } Q_ASSERT(glyph_pos != -1); - int j; - for (j = 0; j < eng->length(item); ++j) - if (logClusters[j] == glyph_pos) - break; -// qDebug("at pos %d (in run: %d)", si.position + j, j); - return si.position + j; + return eng->positionInLigature(&si, end, x, edge, glyph_pos); } } // right of last item diff --git a/tests/auto/qtextlayout/tst_qtextlayout.cpp b/tests/auto/qtextlayout/tst_qtextlayout.cpp index b5712fb..e68a65e 100644 --- a/tests/auto/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/qtextlayout/tst_qtextlayout.cpp @@ -128,6 +128,7 @@ private slots: void textWidthWithStackedTextEngine(); void textWidthWithLineSeparator(); void cursorInLigatureWithMultipleLines(); + void xToCursorForLigatures(); private: QFont testFont; @@ -1477,5 +1478,29 @@ void tst_QTextLayout::cursorInLigatureWithMultipleLines() QVERIFY(line.cursorToX(0) != line.cursorToX(1)); } +void tst_QTextLayout::xToCursorForLigatures() +{ +#if !defined(Q_WS_MAC) + QSKIP("This test can not be run on Mac", SkipAll); +#endif + QTextLayout layout("fi", QFont("Times", 20)); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QVERIFY(line.xToCursor(0) != line.xToCursor(line.naturalTextWidth() / 2)); + + // U+0061 U+0308 + QTextLayout layout2(QString::fromUtf8("\x61\xCC\x88"), QFont("Times", 20)); + + layout2.beginLayout(); + line = layout2.createLine(); + layout2.endLayout(); + + qreal width = line.naturalTextWidth(); + QVERIFY(line.xToCursor(0) == line.xToCursor(width / 2) || + line.xToCursor(width) == line.xToCursor(width / 2)); +} + QTEST_MAIN(tst_QTextLayout) #include "tst_qtextlayout.moc" -- cgit v0.12 From ddfd45c1be13f695b106f10af7a4d0bc66059df6 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Mon, 23 May 2011 14:25:53 +0200 Subject: Revert the revert of subpixel positions interpretation for text So that text rendering with raster engine on Mac can be the same as with native engine. Reviewed-by: Eskil --- src/gui/painting/qpaintengine_raster.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 7dda940..592bf12 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2880,7 +2880,6 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, rightShift = 3; // divide by 8 int margin = cache->glyphMargin(); - const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); for (int i=0; i Date: Tue, 24 May 2011 12:30:57 +0200 Subject: Move wayland headers files to 3rdparty due to copyright issues Reviewed-by: Paul Olav Tvete --- .../qwaylandwindowmanager-client-protocol.h | 82 ++++++++++++++++++++++ .../wayland/wayland-windowmanager-protocol.c | 36 ++++++++++ .../qwaylandwindowmanager-client-protocol.h | 82 ---------------------- .../wayland-windowmanager-protocol.c | 36 ---------- 4 files changed, 118 insertions(+), 118 deletions(-) create mode 100644 src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h create mode 100644 src/3rdparty/wayland/wayland-windowmanager-protocol.c delete mode 100644 src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h delete mode 100644 src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c diff --git a/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h new file mode 100644 index 0000000..ec776c5 --- /dev/null +++ b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2010 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + +#ifndef WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H +#define WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-util.h" + +struct wl_client; + +struct wl_windowmanager; + +extern const struct wl_interface wl_windowmanager_interface; + +#define WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0 + +static inline struct wl_windowmanager * +wl_windowmanager_create(struct wl_display *display, uint32_t id, uint32_t /*version*/) +{ + // ### does not run without latest wayland. must be enabled later + //wl_display_bind(display, id, "wl_windowmanager", version); + + return (struct wl_windowmanager *) + wl_proxy_create_for_id(display, &wl_windowmanager_interface, id); +} + +static inline void +wl_windowmanager_set_user_data(struct wl_windowmanager *wl_windowmanager, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wl_windowmanager, user_data); +} + +static inline void * +wl_windowmanager_get_user_data(struct wl_windowmanager *wl_windowmanager) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wl_windowmanager); +} + +static inline void +wl_windowmanager_destroy(struct wl_windowmanager *wl_windowmanager) +{ + wl_proxy_destroy((struct wl_proxy *) wl_windowmanager); +} + +static inline void +wl_windowmanager_map_client_to_process(struct wl_windowmanager *wl_windowmanager, uint32_t processid) +{ + wl_proxy_marshal((struct wl_proxy *) wl_windowmanager, + WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/3rdparty/wayland/wayland-windowmanager-protocol.c b/src/3rdparty/wayland/wayland-windowmanager-protocol.c new file mode 100644 index 0000000..48049d8 --- /dev/null +++ b/src/3rdparty/wayland/wayland-windowmanager-protocol.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2010 Kristian Høgsberg + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + +#include +#include +#include "wayland-util.h" + +static const struct wl_message wl_windowmanager_requests[] = { + { "map_client_to_process", "u", NULL }, +}; + +WL_EXPORT const struct wl_interface wl_windowmanager_interface = { + "wl_windowmanager", 1, + ARRAY_LENGTH(wl_windowmanager_requests), wl_windowmanager_requests, + 0, NULL, +}; diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h deleted file mode 100644 index ec776c5..0000000 --- a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanager-client-protocol.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright © 2010 Kristian Høgsberg - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - - -#ifndef WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H -#define WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "wayland-util.h" - -struct wl_client; - -struct wl_windowmanager; - -extern const struct wl_interface wl_windowmanager_interface; - -#define WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0 - -static inline struct wl_windowmanager * -wl_windowmanager_create(struct wl_display *display, uint32_t id, uint32_t /*version*/) -{ - // ### does not run without latest wayland. must be enabled later - //wl_display_bind(display, id, "wl_windowmanager", version); - - return (struct wl_windowmanager *) - wl_proxy_create_for_id(display, &wl_windowmanager_interface, id); -} - -static inline void -wl_windowmanager_set_user_data(struct wl_windowmanager *wl_windowmanager, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) wl_windowmanager, user_data); -} - -static inline void * -wl_windowmanager_get_user_data(struct wl_windowmanager *wl_windowmanager) -{ - return wl_proxy_get_user_data((struct wl_proxy *) wl_windowmanager); -} - -static inline void -wl_windowmanager_destroy(struct wl_windowmanager *wl_windowmanager) -{ - wl_proxy_destroy((struct wl_proxy *) wl_windowmanager); -} - -static inline void -wl_windowmanager_map_client_to_process(struct wl_windowmanager *wl_windowmanager, uint32_t processid) -{ - wl_proxy_marshal((struct wl_proxy *) wl_windowmanager, - WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c b/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c deleted file mode 100644 index 48049d8..0000000 --- a/src/plugins/platforms/wayland/windowmanager_integration/wayland-windowmanager-protocol.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright © 2010 Kristian Høgsberg - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - - -#include -#include -#include "wayland-util.h" - -static const struct wl_message wl_windowmanager_requests[] = { - { "map_client_to_process", "u", NULL }, -}; - -WL_EXPORT const struct wl_interface wl_windowmanager_interface = { - "wl_windowmanager", 1, - ARRAY_LENGTH(wl_windowmanager_requests), wl_windowmanager_requests, - 0, NULL, -}; -- cgit v0.12 From 727f5e50447bf47040746a7a37d488204b279171 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt Date: Tue, 24 May 2011 12:31:16 +0200 Subject: Refer to 3rdparty in windowmanagerintegration headers Reviewed-by: Paul Olav Tvete --- .../windowmanager_integration/windowmanager_integration.pri | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri index a282182..664389a 100644 --- a/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri +++ b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri @@ -3,14 +3,14 @@ DEFINES += QT_WAYLAND_WINDOWMANAGER_SUPPORT contains(DEFINES, QT_WAYLAND_WINDOWMANAGER_SUPPORT) { HEADERS += \ - $$PWD/qwaylandwindowmanager-client-protocol.h \ $$PWD/qwaylandwindowmanagerintegration.h SOURCES += \ - $$PWD/qwaylandwindowmanagerintegration.cpp \ - $$PWD/wayland-windowmanager-protocol.c + $$PWD/qwaylandwindowmanagerintegration.cpp + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/wayland + HEADERS += \ + $$QT_SOURCE_TREE/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h + SOURCES += \ + $$QT_SOURCE_TREE/src/3rdparty/wayland/wayland-windowmanager-protocol.c } - - - -- cgit v0.12 From 2552c99cfeaaba44db77467bf50176173ff14457 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 25 May 2011 10:55:52 +0200 Subject: Fix cursor position test on CursorOnCharacter case Reviewed-by: TrustMe --- src/gui/text/qtextengine.cpp | 5 ++++- src/gui/text/qtextengine_p.h | 2 +- src/gui/text/qtextlayout.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 0df543b..9bbc4a4 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2844,7 +2844,8 @@ int QTextEngine::getClusterLength(unsigned short *logClusters, } int QTextEngine::positionInLigature(const QScriptItem *si, int end, - QFixed x, QFixed edge, int glyph_pos) + QFixed x, QFixed edge, int glyph_pos, + bool cursorOnCharacter) { unsigned short *logClusters = this->logClusters(si); int clusterStart = -1; @@ -2882,6 +2883,8 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, int n = ((x - left) / perItemWidth).floor().toInt(); QFixed dist = x - left - n * perItemWidth; int closestItem = dist > (perItemWidth / 2) ? n + 1 : n; + if (cursorOnCharacter && closestItem > 0) + closestItem--; int pos = si->position + clusterStart + closestItem; // Jump to the next charStop while (!attrs[pos].charStop && pos < end) diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 8e1d796..90e931c 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -620,7 +620,7 @@ public: QFixed leadingSpaceWidth(const QScriptLine &line); QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos); - int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos); + int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter); int previousLogicalPosition(int oldPos) const; int nextLogicalPosition(int oldPos) const; int lineNumberForTextPosition(int pos); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 20edb87..8ec3edf 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2780,11 +2780,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (rtl && nchars > 0) return insertionPoints[lastLine ? nchars : nchars - 1]; } - return eng->positionInLigature(&si, end, x, pos, -1); + return eng->positionInLigature(&si, end, x, pos, -1, + cpos == QTextLine::CursorOnCharacter); } } Q_ASSERT(glyph_pos != -1); - return eng->positionInLigature(&si, end, x, edge, glyph_pos); + return eng->positionInLigature(&si, end, x, edge, glyph_pos, + cpos == QTextLine::CursorOnCharacter); } } // right of last item -- cgit v0.12 From a6642e4659b3d45ffa94f9a3c6413124d49f2b91 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 25 May 2011 11:21:53 +0200 Subject: Fix QFontEngineX11FT compilation xglyph_format is only available when XRender is present. Reviewed-by: Fabien Freling --- src/gui/text/qfontengine_x11.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp index 4260b85..9775e10 100644 --- a/src/gui/text/qfontengine_x11.cpp +++ b/src/gui/text/qfontengine_x11.cpp @@ -1205,7 +1205,9 @@ QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const delete fe; return 0; } else { +#ifndef QT_NO_XRENDER fe->xglyph_format = xglyph_format; +#endif return fe; } } -- cgit v0.12 From dffe4d8d180e34955ebe23540e37ce7ba0d76853 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt Date: Wed, 25 May 2011 11:24:37 +0200 Subject: Add authentication token support for wayland windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For compositors that support it, the wayland clients can associate themselves with an auth token, specified by WL_AUTHENTICATION_TOKEN env var, or by directly specifying it in the wayland client plugin. Reviewed-by: Samuel Rødal --- .../qwaylandwindowmanager-client-protocol.h | 40 ++++++++++++++++++---- .../wayland/wayland-windowmanager-protocol.c | 3 +- src/plugins/platforms/wayland/qwaylanddisplay.cpp | 9 ++--- src/plugins/platforms/wayland/qwaylandwindow.cpp | 1 + .../qwaylandwindowmanagerintegration.cpp | 13 +++++-- .../qwaylandwindowmanagerintegration.h | 1 + 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h index ec776c5..73673ae 100644 --- a/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h +++ b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h @@ -36,16 +36,37 @@ struct wl_client; struct wl_windowmanager; +struct wl_proxy; + +extern void +wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...); +extern struct wl_proxy * +wl_proxy_create(struct wl_proxy *factory, + const struct wl_interface *interface); +extern struct wl_proxy * +wl_proxy_create_for_id(struct wl_display *display, + const struct wl_interface *interface, uint32_t id); +extern void +wl_proxy_destroy(struct wl_proxy *proxy); + +extern int +wl_proxy_add_listener(struct wl_proxy *proxy, + void (**implementation)(void), void *data); + +extern void +wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data); + +extern void * +wl_proxy_get_user_data(struct wl_proxy *proxy); + extern const struct wl_interface wl_windowmanager_interface; -#define WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0 +#define wl_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0 +#define wl_WINDOWMANAGER_AUTHENTICATE_WITH_TOKEN 1 static inline struct wl_windowmanager * -wl_windowmanager_create(struct wl_display *display, uint32_t id, uint32_t /*version*/) +wl_windowmanager_create(struct wl_display *display, uint32_t id) { - // ### does not run without latest wayland. must be enabled later - //wl_display_bind(display, id, "wl_windowmanager", version); - return (struct wl_windowmanager *) wl_proxy_create_for_id(display, &wl_windowmanager_interface, id); } @@ -72,7 +93,14 @@ static inline void wl_windowmanager_map_client_to_process(struct wl_windowmanager *wl_windowmanager, uint32_t processid) { wl_proxy_marshal((struct wl_proxy *) wl_windowmanager, - WL_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid); + wl_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid); +} + +static inline void +wl_windowmanager_authenticate_with_token(struct wl_windowmanager *wl_windowmanager, const char *wl_authentication_token) +{ + wl_proxy_marshal((struct wl_proxy *) wl_windowmanager, + wl_WINDOWMANAGER_AUTHENTICATE_WITH_TOKEN, wl_authentication_token); } #ifdef __cplusplus diff --git a/src/3rdparty/wayland/wayland-windowmanager-protocol.c b/src/3rdparty/wayland/wayland-windowmanager-protocol.c index 48049d8..0250801 100644 --- a/src/3rdparty/wayland/wayland-windowmanager-protocol.c +++ b/src/3rdparty/wayland/wayland-windowmanager-protocol.c @@ -26,7 +26,8 @@ #include "wayland-util.h" static const struct wl_message wl_windowmanager_requests[] = { - { "map_client_to_process", "u", NULL }, + { "map_client_to_process", "u" }, + { "authenticate_with_token", "s" }, }; WL_EXPORT const struct wl_interface wl_windowmanager_interface = { diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index dcfaf0f..da908fb 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -137,6 +137,11 @@ QWaylandDisplay::QWaylandDisplay(void) #ifdef QT_WAYLAND_GL_SUPPORT mEglIntegration = QWaylandGLIntegration::createGLIntegration(this); #endif + +#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT + mWindowManagerIntegration = QWaylandWindowManagerIntegration::createIntegration(this); +#endif + blockingReadEvents(); qRegisterMetaType("uint32_t"); @@ -145,10 +150,6 @@ QWaylandDisplay::QWaylandDisplay(void) mEglIntegration->initialize(); #endif -#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT - mWindowManagerIntegration = QWaylandWindowManagerIntegration::createIntegration(this); -#endif - connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(flushRequests())); mFd = wl_display_get_fd(mDisplay, sourceUpdate, this); diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index d2a7647..2bfc643 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -67,6 +67,7 @@ QWaylandWindow::QWaylandWindow(QWidget *window) #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT mDisplay->windowManagerIntegration()->mapClientToProcess(qApp->applicationPid()); + mDisplay->windowManagerIntegration()->authenticateWithToken(); #endif mSurface = mDisplay->createSurface(this); diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp index b93e6d2..e4a6218 100644 --- a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp @@ -68,12 +68,11 @@ struct wl_windowmanager *QWaylandWindowManagerIntegration::windowManager() const return mWaylandWindowManager; } -void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(wl_display *display, uint32_t id, const char *interface, - uint32_t version, void *data) +void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(wl_display *display, uint32_t id, const char *interface, uint32_t version, void *data) { if (strcmp(interface, "wl_windowmanager") == 0) { QWaylandWindowManagerIntegration *integration = static_cast(data); - integration->mWaylandWindowManager = wl_windowmanager_create(display,id, version); + integration->mWaylandWindowManager = wl_windowmanager_create(display, id); } } @@ -83,3 +82,11 @@ void QWaylandWindowManagerIntegration::mapClientToProcess(long long processId) wl_windowmanager_map_client_to_process(mWaylandWindowManager, (uint32_t) processId); } +void QWaylandWindowManagerIntegration::authenticateWithToken(const QByteArray &token) +{ + QByteArray authToken = token; + if (authToken.isEmpty()) + authToken = qgetenv("WL_AUTHENTICATION_TOKEN"); + if (mWaylandWindowManager) + wl_windowmanager_authenticate_with_token(mWaylandWindowManager, authToken.constData()); +} diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h index 01a7bdd..a79f205 100644 --- a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h +++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h @@ -56,6 +56,7 @@ public: void mapSurfaceToProcess(struct wl_surface *surface, long long processId); void mapClientToProcess(long long processId); + void authenticateWithToken(const QByteArray &token = QByteArray()); private: static void wlHandleListenerGlobal(wl_display *display, uint32_t id, -- cgit v0.12 From 31110bf84bb06d57983501fa65fe0db3f7c61927 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 25 May 2011 18:24:30 +0200 Subject: Fix boundry conditions for cursor hit test Clicking at the edge of a glyph means lookup for the left glyph. Reviewed-by: TrustMe --- src/gui/text/qtextengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 9bbc4a4..5bf2b12 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2867,7 +2867,7 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, if (glyph_pos == -1 && end > 0) glyph_pos = logClusters[end - 1]; else { - if (x < edge) + if (x <= edge) glyph_pos--; } -- cgit v0.12 From 35421a9313a324ff63df6ba27e03b8090c964717 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 27 May 2011 14:24:21 +0200 Subject: Fix compile for systems with old fontconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia26796bdbab7988d14163d3c1290111c0cb22bf7 Reviewed-on: http://codereview.qt.nokia.com/182 Reviewed-by: Samuel Rødal (cherry picked from commit 93339428c040a2576e4e0da315b1a6a4e4c1916f) --- src/gui/text/qfontdatabase_x11.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index 0c0c4c8..cb63844 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -1996,6 +1996,11 @@ void QFontDatabase::load(const QFontPrivate *d, int script) QFontCache::instance()->insertEngine(key, fe); } +// Needed for fontconfig version < 2.2.97 +#ifndef FC_FAMILYLANG +#define FC_FAMILYLANG "familylang" +#endif + static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) { #if defined(QT_NO_FONTCONFIG) -- cgit v0.12 From 93bce7874721de905af0181da95c58fe13a2e015 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Tue, 24 May 2011 11:50:16 +0200 Subject: Keep line consistency with text baseline Also revert previous underline patch. Reviewed-by: Eskil --- src/gui/painting/qpaintengine_raster.cpp | 3 ++- src/gui/painting/qpainter.cpp | 3 +-- src/gui/painting/qtextureglyphcache.cpp | 4 +++- src/gui/text/qfontengine_coretext.mm | 8 ++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 592bf12..730f6a2 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2880,6 +2880,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, rightShift = 3; // divide by 8 int margin = cache->glyphMargin(); + const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); for (int i=0; iunderlinePosition().toReal(); // deliberately ceil the offset to avoid the underline coming too close to // the text above it. - const qreal aliasedCoordinateDelta = 0.5 - 0.015625; - const qreal underlinePos = pos.y() + qCeil(underlineOffset) - aliasedCoordinateDelta; + const qreal underlinePos = pos.y() + qCeil(underlineOffset); if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle)); diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index e9e56a2..5d397be 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -367,7 +367,9 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) || defined(Q_WS_X11) +#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) + return 1; +#elif defined(Q_WS_X11) return 0; #else return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index d14db3a..982c271 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -730,10 +730,10 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position } } -QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa) +QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool aa) { const glyph_metrics_t br = boundingBox(glyph); - QImage im(qRound(br.width)+2, qRound(br.height)+2, QImage::Format_RGB32); + QImage im(qRound(br.width) + margin * 2, qRound(br.height) + margin * 2, QImage::Format_RGB32); im.fill(0); CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); @@ -765,8 +765,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition CGContextSetFont(ctx, cgFont); - qreal pos_x = -br.x.toReal() + subPixelPosition.toReal(); - qreal pos_y = im.height() + br.y.toReal() - 1; + qreal pos_x = -br.x.toReal() + subPixelPosition.toReal() + margin; + qreal pos_y = im.height() + br.y.toReal() - margin; CGContextSetTextPosition(ctx, pos_x, pos_y); CGSize advance; -- cgit v0.12 From bc800ea78418061bc379bfb206a99f64c2ee1ed9 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 6 May 2011 18:36:43 +0200 Subject: Added Wayland selection support. --- src/gui/kernel/qclipboard.h | 1 + src/gui/kernel/qplatformclipboard_qpa.cpp | 7 + src/gui/kernel/qplatformclipboard_qpa.h | 1 + .../platforms/wayland/qwaylandclipboard.cpp | 242 +++++++++++++++++++++ src/plugins/platforms/wayland/qwaylandclipboard.h | 86 ++++++++ src/plugins/platforms/wayland/qwaylanddisplay.cpp | 7 +- src/plugins/platforms/wayland/qwaylanddisplay.h | 1 + .../platforms/wayland/qwaylandinputdevice.h | 1 + .../platforms/wayland/qwaylandintegration.cpp | 9 + .../platforms/wayland/qwaylandintegration.h | 3 + src/plugins/platforms/wayland/wayland.pro | 6 +- 11 files changed, 361 insertions(+), 3 deletions(-) create mode 100644 src/plugins/platforms/wayland/qwaylandclipboard.cpp create mode 100644 src/plugins/platforms/wayland/qwaylandclipboard.h diff --git a/src/gui/kernel/qclipboard.h b/src/gui/kernel/qclipboard.h index b55bdc6..019917e 100644 --- a/src/gui/kernel/qclipboard.h +++ b/src/gui/kernel/qclipboard.h @@ -112,6 +112,7 @@ protected: friend class QBaseApplication; friend class QDragManager; friend class QMimeSource; + friend class QPlatformClipboard; private: Q_DISABLE_COPY(QClipboard) diff --git a/src/gui/kernel/qplatformclipboard_qpa.cpp b/src/gui/kernel/qplatformclipboard_qpa.cpp index 957a4df..33d2afc 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.cpp +++ b/src/gui/kernel/qplatformclipboard_qpa.cpp @@ -42,6 +42,8 @@ #ifndef QT_NO_CLIPBOARD +#include + QT_BEGIN_NAMESPACE class QClipboardData @@ -100,6 +102,11 @@ bool QPlatformClipboard::supportsMode(QClipboard::Mode mode) const return mode == QClipboard::Clipboard; } +void QPlatformClipboard::emitChanged(QClipboard::Mode mode) +{ + QApplication::clipboard()->emitChanged(mode); +} + QT_END_NAMESPACE #endif //QT_NO_CLIPBOARD diff --git a/src/gui/kernel/qplatformclipboard_qpa.h b/src/gui/kernel/qplatformclipboard_qpa.h index 3381c06..5444a1f 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.h +++ b/src/gui/kernel/qplatformclipboard_qpa.h @@ -62,6 +62,7 @@ public: virtual const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard ) const; virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); virtual bool supportsMode(QClipboard::Mode mode) const; + void emitChanged(QClipboard::Mode mode); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp new file mode 100644 index 0000000..9c533aa --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandclipboard.h" +#include "qwaylanddisplay.h" +#include "qwaylandinputdevice.h" +#include +#include +#include +#include +#include +#include + +static QWaylandClipboard *clipboard; + +class QWaylandSelection +{ +public: + QWaylandSelection(QWaylandDisplay *display, QMimeData *data); + ~QWaylandSelection(); + +private: + static uint32_t getTime(); + static void send(void *data, struct wl_selection *selection, const char *mime_type, int fd); + static void cancelled(void *data, struct wl_selection *selection); + static const struct wl_selection_listener selectionListener; + + QMimeData *mMimeData; + struct wl_selection *mSelection; +}; + +const struct wl_selection_listener QWaylandSelection::selectionListener = { + QWaylandSelection::send, + QWaylandSelection::cancelled +}; + +uint32_t QWaylandSelection::getTime() +{ + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +QWaylandSelection::QWaylandSelection(QWaylandDisplay *display, QMimeData *data) + : mMimeData(data), mSelection(0) +{ + struct wl_shell *shell = display->wl_shell(); + mSelection = wl_shell_create_selection(shell); + wl_selection_add_listener(mSelection, &selectionListener, this); + foreach (const QString &format, data->formats()) + wl_selection_offer(mSelection, format.toLatin1().constData()); + wl_selection_activate(mSelection, + display->inputDevices().at(0)->wl_input_device(), + getTime()); +} + +QWaylandSelection::~QWaylandSelection() +{ + if (mSelection) { + clipboard->unregisterSelection(this); + wl_selection_destroy(mSelection); + } + delete mMimeData; +} + +void QWaylandSelection::send(void *data, + struct wl_selection *selection, + const char *mime_type, + int fd) +{ + Q_UNUSED(selection); + QWaylandSelection *self = static_cast(data); + QString mimeType = QString::fromLatin1(mime_type); + QByteArray content = self->mMimeData->data(mimeType); + if (!content.isEmpty()) { + QFile f; + if (f.open(fd, QIODevice::WriteOnly)) + f.write(content); + } + close(fd); +} + +void QWaylandSelection::cancelled(void *data, struct wl_selection *selection) +{ + Q_UNUSED(selection); + delete static_cast(data); +} + +QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display) + : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0) +{ + clipboard = this; +} + +QWaylandClipboard::~QWaylandClipboard() +{ + if (mOffer) + wl_selection_offer_destroy(mOffer); + delete mMimeDataIn; + qDeleteAll(mSelections); +} + +void QWaylandClipboard::unregisterSelection(QWaylandSelection *selection) +{ + mSelections.removeOne(selection); +} + +void QWaylandClipboard::syncCallback(void *data) +{ + *static_cast(data) = true; +} + +void QWaylandClipboard::forceRoundtrip(struct wl_display *display) +{ + bool done = false; + wl_display_sync_callback(display, syncCallback, &done); + wl_display_iterate(display, WL_DISPLAY_WRITABLE); + while (!done) + wl_display_iterate(display, WL_DISPLAY_READABLE); +} + +const QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) const +{ + Q_ASSERT(mode == QClipboard::Clipboard); + if (!mMimeDataIn) + mMimeDataIn = new QMimeData; + mMimeDataIn->clear(); + if (!mOfferedMimeTypes.isEmpty() && mOffer) { + foreach (const QString &mimeType, mOfferedMimeTypes) { + int pipefd[2]; + if (pipe(pipefd) == -1) { + qWarning("QWaylandClipboard::mimedata: pipe() failed"); + break; + } + QByteArray mimeTypeBa = mimeType.toLatin1(); + wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]); + QByteArray content; + forceRoundtrip(mDisplay->wl_display()); + char buf[256]; + int n; + close(pipefd[1]); + while ((n = read(pipefd[0], &buf, sizeof buf)) > 0) + content.append(buf, n); + close(pipefd[0]); + mMimeDataIn->setData(mimeType, content); + } + } + return mMimeDataIn; +} + +void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + Q_ASSERT(mode == QClipboard::Clipboard); + if (!mDisplay->inputDevices().isEmpty()) { + if (!data) + data = new QMimeData; + mSelection = new QWaylandSelection(mDisplay, data); + } else { + qWarning("QWaylandClipboard::setMimeData: No input devices"); + } +} + +bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +const struct wl_selection_offer_listener QWaylandClipboard::selectionOfferListener = { + QWaylandClipboard::offer, + QWaylandClipboard::keyboardFocus +}; + +void QWaylandClipboard::createSelectionOffer(uint32_t id) +{ + mOfferedMimeTypes.clear(); + if (mOffer) + wl_selection_offer_destroy(mOffer); + mOffer = 0; + struct wl_selection_offer *offer = wl_selection_offer_create(mDisplay->wl_display(), id, 1); + wl_selection_offer_add_listener(offer, &selectionOfferListener, this); +} + +void QWaylandClipboard::offer(void *data, + struct wl_selection_offer *selection_offer, + const char *type) +{ + Q_UNUSED(selection_offer); + QWaylandClipboard *self = static_cast(data); + self->mOfferedMimeTypes.append(QString::fromLatin1(type)); +} + +void QWaylandClipboard::keyboardFocus(void *data, + struct wl_selection_offer *selection_offer, + wl_input_device *input_device) +{ + QWaylandClipboard *self = static_cast(data); + if (!input_device) { + wl_selection_offer_destroy(selection_offer); + self->mOffer = 0; + return; + } + self->mOffer = selection_offer; + self->emitChanged(QClipboard::Clipboard); +} diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h new file mode 100644 index 0000000..606a1f6 --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandclipboard.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDCLIPBOARD_H +#define QWAYLANDCLIPBOARD_H + +#include +#include + +class QWaylandDisplay; +class QWaylandSelection; +struct wl_selection_offer; + +class QWaylandClipboard : public QPlatformClipboard +{ +public: + QWaylandClipboard(QWaylandDisplay *display); + ~QWaylandClipboard(); + + const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) const; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); + bool supportsMode(QClipboard::Mode mode) const; + + void unregisterSelection(QWaylandSelection *selection); + + void createSelectionOffer(uint32_t id); + +private: + static void offer(void *data, + struct wl_selection_offer *selection_offer, + const char *type); + static void keyboardFocus(void *data, + struct wl_selection_offer *selection_offer, + struct wl_input_device *input_device); + static const struct wl_selection_offer_listener selectionOfferListener; + + static void syncCallback(void *data); + static void forceRoundtrip(struct wl_display *display); + + QWaylandDisplay *mDisplay; + QWaylandSelection *mSelection; + mutable QMimeData *mMimeDataIn; + QList mSelections; + QStringList mOfferedMimeTypes; + struct wl_selection_offer *mOffer; +}; + +#endif // QWAYLANDCLIPBOARD_H diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index da908fb..c3eb7f4 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -45,6 +45,7 @@ #include "qwaylandscreen.h" #include "qwaylandcursor.h" #include "qwaylandinputdevice.h" +#include "qwaylandclipboard.h" #ifdef QT_WAYLAND_GL_SUPPORT #include "gl_integration/qwaylandglintegration.h" @@ -56,6 +57,7 @@ #include #include +#include #include #include @@ -265,7 +267,6 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, uint32_t version) { Q_UNUSED(version); - if (interface == "wl_output") { struct wl_output *output = wl_output_create(mDisplay, id, 1); wl_output_add_listener(output, &outputListener, this); @@ -280,5 +281,9 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, QWaylandInputDevice *inputDevice = new QWaylandInputDevice(mDisplay, id); mInputDevices.append(inputDevice); + } else if (interface == "wl_selection_offer") { + QPlatformIntegration *plat = QApplicationPrivate::platformIntegration(); + QWaylandClipboard *clipboard = static_cast(plat->clipboard()); + clipboard->createSelectionOffer(id); } } diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h index 81deb3d..6266360 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay.h @@ -87,6 +87,7 @@ public: void frameCallback(wl_display_frame_func_t func, struct wl_surface *surface, void *data); struct wl_display *wl_display() const { return mDisplay; } + struct wl_shell *wl_shell() const { return mShell; } QList inputDevices() const { return mInputDevices; } diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.h b/src/plugins/platforms/wayland/qwaylandinputdevice.h index 3c83252..251259b 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.h @@ -60,6 +60,7 @@ public: QWaylandInputDevice(struct wl_display *display, uint32_t id); void attach(QWaylandBuffer *buffer, int x, int y); void handleWindowDestroyed(QWaylandWindow *window); + struct wl_input_device *wl_input_device() const { return mInputDevice; } private: struct wl_display *mDisplay; diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index b6401f6..6166c14 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -45,6 +45,7 @@ #include "qwaylandshmsurface.h" #include "qwaylandshmwindow.h" #include "qwaylandnativeinterface.h" +#include "qwaylandclipboard.h" #include "qgenericunixfontdatabase.h" @@ -64,6 +65,7 @@ QWaylandIntegration::QWaylandIntegration(bool useOpenGL) , mDisplay(new QWaylandDisplay()) , mUseOpenGL(useOpenGL) , mNativeInterface(new QWaylandNativeInterface) + , mClipboard(0) { } @@ -132,3 +134,10 @@ bool QWaylandIntegration::hasOpenGL() const return false; #endif } + +QPlatformClipboard *QWaylandIntegration::clipboard() const +{ + if (!mClipboard) + mClipboard = new QWaylandClipboard(mDisplay); + return mClipboard; +} diff --git a/src/plugins/platforms/wayland/qwaylandintegration.h b/src/plugins/platforms/wayland/qwaylandintegration.h index 71f6d9c..fc748b0 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.h +++ b/src/plugins/platforms/wayland/qwaylandintegration.h @@ -65,6 +65,8 @@ public: QPlatformNativeInterface *nativeInterface() const; + QPlatformClipboard *clipboard() const; + private: bool hasOpenGL() const; @@ -72,6 +74,7 @@ private: QWaylandDisplay *mDisplay; bool mUseOpenGL; QPlatformNativeInterface *mNativeInterface; + mutable QPlatformClipboard *mClipboard; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index d2498b2..19f7ca3 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -15,7 +15,8 @@ SOURCES = main.cpp \ qwaylanddisplay.cpp \ qwaylandwindow.cpp \ qwaylandscreen.cpp \ - qwaylandshmwindow.cpp + qwaylandshmwindow.cpp \ + qwaylandclipboard.cpp HEADERS = qwaylandintegration.h \ qwaylandnativeinterface.h \ @@ -25,7 +26,8 @@ HEADERS = qwaylandintegration.h \ qwaylandscreen.h \ qwaylandshmsurface.h \ qwaylandbuffer.h \ - qwaylandshmwindow.h + qwaylandshmwindow.h \ + qwaylandclipboard.h INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND LIBS += $$QMAKE_LIBS_WAYLAND -- cgit v0.12 From 1a17ab72726ba5d15396ee152c78a1aa921533a6 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 10 May 2011 09:17:27 +0200 Subject: Retrieve the actual data in the Wayland clipboard only when requested. --- .../platforms/wayland/qwaylandclipboard.cpp | 86 ++++++++++++++++------ src/plugins/platforms/wayland/qwaylandclipboard.h | 6 +- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index 9c533aa..9a363b5 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -48,9 +48,48 @@ #include #include #include +#include static QWaylandClipboard *clipboard; +class QWaylandMimeData : public QInternalMimeData +{ +public: + void clearAll(); + void setFormats(const QStringList &formatList); + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; +private: + QStringList mFormatList; +}; + +void QWaylandMimeData::clearAll() +{ + clear(); + mFormatList.clear(); +} + +void QWaylandMimeData::setFormats(const QStringList &formatList) +{ + mFormatList = formatList; +} + +bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const +{ + return formats().contains(mimeType); +} + +QStringList QWaylandMimeData::formats_sys() const +{ + return mFormatList; +} + +QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const +{ + return clipboard->retrieveData(mimeType, type); +} + class QWaylandSelection { public: @@ -157,32 +196,35 @@ void QWaylandClipboard::forceRoundtrip(struct wl_display *display) wl_display_iterate(display, WL_DISPLAY_READABLE); } +QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type type) const +{ + Q_UNUSED(type); + int pipefd[2]; + if (pipe(pipefd) == -1) { + qWarning("QWaylandClipboard: pipe() failed"); + return QVariant(); + } + QByteArray mimeTypeBa = mimeType.toLatin1(); + wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]); + QByteArray content; + forceRoundtrip(mDisplay->wl_display()); + char buf[256]; + int n; + close(pipefd[1]); + while ((n = read(pipefd[0], &buf, sizeof buf)) > 0) + content.append(buf, n); + close(pipefd[0]); + return content; +} + const QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) const { Q_ASSERT(mode == QClipboard::Clipboard); if (!mMimeDataIn) - mMimeDataIn = new QMimeData; - mMimeDataIn->clear(); - if (!mOfferedMimeTypes.isEmpty() && mOffer) { - foreach (const QString &mimeType, mOfferedMimeTypes) { - int pipefd[2]; - if (pipe(pipefd) == -1) { - qWarning("QWaylandClipboard::mimedata: pipe() failed"); - break; - } - QByteArray mimeTypeBa = mimeType.toLatin1(); - wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]); - QByteArray content; - forceRoundtrip(mDisplay->wl_display()); - char buf[256]; - int n; - close(pipefd[1]); - while ((n = read(pipefd[0], &buf, sizeof buf)) > 0) - content.append(buf, n); - close(pipefd[0]); - mMimeDataIn->setData(mimeType, content); - } - } + mMimeDataIn = new QWaylandMimeData; + mMimeDataIn->clearAll(); + if (!mOfferedMimeTypes.isEmpty() && mOffer) + mMimeDataIn->setFormats(mOfferedMimeTypes); return mMimeDataIn; } diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h index 606a1f6..b0d6394 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.h +++ b/src/plugins/platforms/wayland/qwaylandclipboard.h @@ -44,9 +44,11 @@ #include #include +#include class QWaylandDisplay; class QWaylandSelection; +class QWaylandMimeData; struct wl_selection_offer; class QWaylandClipboard : public QPlatformClipboard @@ -63,6 +65,8 @@ public: void createSelectionOffer(uint32_t id); + QVariant retrieveData(const QString &mimeType, QVariant::Type type) const; + private: static void offer(void *data, struct wl_selection_offer *selection_offer, @@ -77,7 +81,7 @@ private: QWaylandDisplay *mDisplay; QWaylandSelection *mSelection; - mutable QMimeData *mMimeDataIn; + mutable QWaylandMimeData *mMimeDataIn; QList mSelections; QStringList mOfferedMimeTypes; struct wl_selection_offer *mOffer; -- cgit v0.12 From 55a440589c186e389390b2fd18170768901fa618 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 10 May 2011 10:09:44 +0200 Subject: Remove const from QPlatformClipboard::mimeData(). Most implementations will anyway do non-const operations in there, the change avoids the need for const_cast or mutable. --- src/gui/kernel/qplatformclipboard_qpa.cpp | 2 +- src/gui/kernel/qplatformclipboard_qpa.h | 2 +- src/plugins/platforms/wayland/qwaylandclipboard.cpp | 2 +- src/plugins/platforms/wayland/qwaylandclipboard.h | 4 ++-- src/plugins/platforms/xlib/qxlibclipboard.cpp | 8 +++----- src/plugins/platforms/xlib/qxlibclipboard.h | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/gui/kernel/qplatformclipboard_qpa.cpp b/src/gui/kernel/qplatformclipboard_qpa.cpp index 33d2afc..302df68 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.cpp +++ b/src/gui/kernel/qplatformclipboard_qpa.cpp @@ -83,7 +83,7 @@ QPlatformClipboard::~QPlatformClipboard() } -const QMimeData *QPlatformClipboard::mimeData(QClipboard::Mode mode) const +QMimeData *QPlatformClipboard::mimeData(QClipboard::Mode mode) { //we know its clipboard Q_UNUSED(mode); diff --git a/src/gui/kernel/qplatformclipboard_qpa.h b/src/gui/kernel/qplatformclipboard_qpa.h index 5444a1f..e1be8aa 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.h +++ b/src/gui/kernel/qplatformclipboard_qpa.h @@ -59,7 +59,7 @@ class Q_GUI_EXPORT QPlatformClipboard public: virtual ~QPlatformClipboard(); - virtual const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard ) const; + virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); virtual bool supportsMode(QClipboard::Mode mode) const; void emitChanged(QClipboard::Mode mode); diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index 9a363b5..c1ac386 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -217,7 +217,7 @@ QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type return content; } -const QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) const +QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) { Q_ASSERT(mode == QClipboard::Clipboard); if (!mMimeDataIn) diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h index b0d6394..6a02254 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.h +++ b/src/plugins/platforms/wayland/qwaylandclipboard.h @@ -57,7 +57,7 @@ public: QWaylandClipboard(QWaylandDisplay *display); ~QWaylandClipboard(); - const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) const; + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); bool supportsMode(QClipboard::Mode mode) const; @@ -81,7 +81,7 @@ private: QWaylandDisplay *mDisplay; QWaylandSelection *mSelection; - mutable QWaylandMimeData *mMimeDataIn; + QWaylandMimeData *mMimeDataIn; QList mSelections; QStringList mOfferedMimeTypes; struct wl_selection_offer *mOffer; diff --git a/src/plugins/platforms/xlib/qxlibclipboard.cpp b/src/plugins/platforms/xlib/qxlibclipboard.cpp index dfaf552..fef6e3a 100644 --- a/src/plugins/platforms/xlib/qxlibclipboard.cpp +++ b/src/plugins/platforms/xlib/qxlibclipboard.cpp @@ -161,12 +161,11 @@ QXlibClipboard::QXlibClipboard(QXlibScreen *screen) { } -const QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) const +QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) { if (mode == QClipboard::Clipboard) { if (!m_xClipboard) { - QXlibClipboard *that = const_cast(this); - that->m_xClipboard = new QXlibClipboardMime(mode,that); + m_xClipboard = new QXlibClipboardMime(mode, this); } Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),QXlibStatic::atom(QXlibStatic::CLIPBOARD)); if (clipboardOwner == owner()) { @@ -176,8 +175,7 @@ const QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) const } } else if (mode == QClipboard::Selection) { if (!m_xSelection) { - QXlibClipboard *that = const_cast(this); - that->m_xSelection = new QXlibClipboardMime(mode,that); + m_xSelection = new QXlibClipboardMime(mode, this); } Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),XA_PRIMARY); if (clipboardOwner == owner()) { diff --git a/src/plugins/platforms/xlib/qxlibclipboard.h b/src/plugins/platforms/xlib/qxlibclipboard.h index 15901b0..d61340d 100644 --- a/src/plugins/platforms/xlib/qxlibclipboard.h +++ b/src/plugins/platforms/xlib/qxlibclipboard.h @@ -51,7 +51,7 @@ class QXlibClipboard : public QPlatformClipboard public: QXlibClipboard(QXlibScreen *screen); - const QMimeData *mimeData(QClipboard::Mode mode) const; + QMimeData *mimeData(QClipboard::Mode mode); void setMimeData(QMimeData *data, QClipboard::Mode mode); bool supportsMode(QClipboard::Mode mode) const; -- cgit v0.12 From 0b57fc57d2c52c3ac58ed7095f236446c9dd97e7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 10 May 2011 18:03:43 +0200 Subject: Prevent crash in wayland mimedata in case there is no offer. --- src/plugins/platforms/wayland/qwaylandclipboard.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index c1ac386..47ca228 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -199,6 +199,8 @@ void QWaylandClipboard::forceRoundtrip(struct wl_display *display) QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type type) const { Q_UNUSED(type); + if (mOfferedMimeTypes.isEmpty() || !mOffer) + return QVariant(); int pipefd[2]; if (pipe(pipefd) == -1) { qWarning("QWaylandClipboard: pipe() failed"); -- cgit v0.12 From 053aef5972636ad76fe9aea0e7425394e91756c5 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 12 May 2011 16:20:03 +0200 Subject: Fix deadlocks in wayland clipboard that can occur in special scenarios. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setMimeData() emits the changed signal always so to prevent duplicated signals keyboardFocus() must only emit when the change came from another wayland client. However direct connection may cause issues when invoking the slot from a wayland callback, so use a metacall to make sure we return from the callback. Unnecessary data transfer and potential deadlock is now also avoided when a client is requesting the mime data from itself. Reviewed-by: Jørgen Lind --- .../platforms/wayland/qwaylandclipboard.cpp | 25 ++++++++++++++-------- src/plugins/platforms/wayland/qwaylandclipboard.h | 9 +++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index 47ca228..cf9c5a7 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -96,7 +96,6 @@ public: QWaylandSelection(QWaylandDisplay *display, QMimeData *data); ~QWaylandSelection(); -private: static uint32_t getTime(); static void send(void *data, struct wl_selection *selection, const char *mime_type, int fd); static void cancelled(void *data, struct wl_selection *selection); @@ -164,7 +163,7 @@ void QWaylandSelection::cancelled(void *data, struct wl_selection *selection) } QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display) - : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0) + : mDisplay(display), mMimeDataIn(0), mOffer(0) { clipboard = this; } @@ -222,6 +221,8 @@ QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) { Q_ASSERT(mode == QClipboard::Clipboard); + if (!mSelections.isEmpty()) + return mSelections.last()->mMimeData; if (!mMimeDataIn) mMimeDataIn = new QWaylandMimeData; mMimeDataIn->clearAll(); @@ -236,7 +237,7 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) if (!mDisplay->inputDevices().isEmpty()) { if (!data) data = new QMimeData; - mSelection = new QWaylandSelection(mDisplay, data); + mSelections.append(new QWaylandSelection(mDisplay, data)); } else { qWarning("QWaylandClipboard::setMimeData: No input devices"); } @@ -266,21 +267,27 @@ void QWaylandClipboard::offer(void *data, struct wl_selection_offer *selection_offer, const char *type) { + Q_UNUSED(data); Q_UNUSED(selection_offer); - QWaylandClipboard *self = static_cast(data); - self->mOfferedMimeTypes.append(QString::fromLatin1(type)); + clipboard->mOfferedMimeTypes.append(QString::fromLatin1(type)); } void QWaylandClipboard::keyboardFocus(void *data, struct wl_selection_offer *selection_offer, wl_input_device *input_device) { - QWaylandClipboard *self = static_cast(data); + Q_UNUSED(data); if (!input_device) { wl_selection_offer_destroy(selection_offer); - self->mOffer = 0; + clipboard->mOffer = 0; return; } - self->mOffer = selection_offer; - self->emitChanged(QClipboard::Clipboard); + clipboard->mOffer = selection_offer; + if (clipboard->mSelections.isEmpty()) + QMetaObject::invokeMethod(&clipboard->mEmitter, "emitChanged", Qt::QueuedConnection); +} + +void QWaylandClipboardSignalEmitter::emitChanged() +{ + clipboard->emitChanged(QClipboard::Clipboard); } diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h index 6a02254..db436b8 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.h +++ b/src/plugins/platforms/wayland/qwaylandclipboard.h @@ -51,6 +51,13 @@ class QWaylandSelection; class QWaylandMimeData; struct wl_selection_offer; +class QWaylandClipboardSignalEmitter : public QObject +{ + Q_OBJECT +public slots: + void emitChanged(); +}; + class QWaylandClipboard : public QPlatformClipboard { public: @@ -80,11 +87,11 @@ private: static void forceRoundtrip(struct wl_display *display); QWaylandDisplay *mDisplay; - QWaylandSelection *mSelection; QWaylandMimeData *mMimeDataIn; QList mSelections; QStringList mOfferedMimeTypes; struct wl_selection_offer *mOffer; + QWaylandClipboardSignalEmitter mEmitter; }; #endif // QWAYLANDCLIPBOARD_H -- cgit v0.12 From 7c2d885d98761fca7624933a92cde7bad113c862 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Mon, 23 May 2011 12:29:54 +0200 Subject: Track Wayland changes The wl_display_get_xxxx_visual() functions have been removed, and are replaced by a compositor event. Reviewed-by: Samuel --- src/plugins/platforms/wayland/qwaylanddisplay.cpp | 34 +++++++++++++++++++++-- src/plugins/platforms/wayland/qwaylanddisplay.h | 6 ++++ src/plugins/platforms/wayland/wayland_sha1.txt | 3 ++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/plugins/platforms/wayland/wayland_sha1.txt diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index c3eb7f4..aee1fa4 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -81,17 +81,17 @@ struct wl_buffer *QWaylandDisplay::createShmBuffer(int fd, struct wl_visual *QWaylandDisplay::rgbVisual() { - return wl_display_get_rgb_visual(mDisplay); + return rgb_visual; } struct wl_visual *QWaylandDisplay::argbVisual() { - return wl_display_get_argb_visual(mDisplay); + return argb_visual; } struct wl_visual *QWaylandDisplay::argbPremultipliedVisual() { - return wl_display_get_premultiplied_argb_visual(mDisplay); + return premultiplied_argb_visual; } #ifdef QT_WAYLAND_GL_SUPPORT @@ -127,6 +127,7 @@ const struct wl_shell_listener QWaylandDisplay::shellListener = { }; QWaylandDisplay::QWaylandDisplay(void) + : argb_visual(0), premultiplied_argb_visual(0), rgb_visual(0) { mDisplay = wl_display_connect(NULL); if (mDisplay == NULL) { @@ -244,6 +245,11 @@ const struct wl_output_listener QWaylandDisplay::outputListener = { QWaylandDisplay::outputHandleGeometry }; +const struct wl_compositor_listener QWaylandDisplay::compositorListener = { + QWaylandDisplay::handleVisual, +}; + + void QWaylandDisplay::waitForScreens() { flushRequests(); @@ -272,6 +278,8 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, wl_output_add_listener(output, &outputListener, this); } else if (interface == "wl_compositor") { mCompositor = wl_compositor_create(mDisplay, id, 1); + wl_compositor_add_listener(mCompositor, + &compositorListener, this); } else if (interface == "wl_shm") { mShm = wl_shm_create(mDisplay, id, 1); } else if (interface == "wl_shell"){ @@ -287,3 +295,23 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, clipboard->createSelectionOffer(id); } } + +void QWaylandDisplay::handleVisual(void *data, + struct wl_compositor *compositor, + uint32_t id, uint32_t token) +{ + QWaylandDisplay *self = static_cast(data); + + switch (token) { + case WL_COMPOSITOR_VISUAL_ARGB32: + self->argb_visual = wl_visual_create(self->mDisplay, id, 1); + break; + case WL_COMPOSITOR_VISUAL_PREMULTIPLIED_ARGB32: + self->premultiplied_argb_visual = + wl_visual_create(self->mDisplay, id, 1); + break; + case WL_COMPOSITOR_VISUAL_XRGB32: + self->rgb_visual = wl_visual_create(self->mDisplay, id, 1); + break; + } +} diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h index 6266360..16ab3f7 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay.h @@ -116,7 +116,10 @@ private: uint32_t mSocketMask; + struct wl_visual *argb_visual, *premultiplied_argb_visual, *rgb_visual; + static const struct wl_output_listener outputListener; + static const struct wl_compositor_listener compositorListener; static int sourceUpdate(uint32_t mask, void *data); static void displayHandleGlobal(struct wl_display *display, uint32_t id, @@ -127,6 +130,9 @@ private: int32_t x, int32_t y, int32_t width, int32_t height); + static void handleVisual(void *data, + struct wl_compositor *compositor, + uint32_t id, uint32_t token); #ifdef QT_WAYLAND_GL_SUPPORT QWaylandGLIntegration *mEglIntegration; #endif diff --git a/src/plugins/platforms/wayland/wayland_sha1.txt b/src/plugins/platforms/wayland/wayland_sha1.txt new file mode 100644 index 0000000..d262437 --- /dev/null +++ b/src/plugins/platforms/wayland/wayland_sha1.txt @@ -0,0 +1,3 @@ +This version of the Qt Wayland plugin is checked against the following sha1 +from the Wayland repository: +eff7fc0d99be2e51eaa351785030c8d374ac71de -- cgit v0.12 From af3efefeefe686e5c35ed502de077c0bcb6f6fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Fri, 27 May 2011 02:12:02 -0700 Subject: We need to let the currentContext be in the same state after setting the new eglsurface --- .../wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp index d293019..aaba5ac 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp @@ -115,8 +115,15 @@ void *QWaylandGLContext::getProcAddress(const QString &string) void QWaylandGLContext::setEglSurface(EGLSurface surface) { - doneCurrent(); + bool wasCurrent = false; + if (QPlatformGLContext::currentContext() == this) { + wasCurrent = true; + doneCurrent(); + } mSurface = surface; + if (wasCurrent) { + makeCurrent(); + } } EGLConfig QWaylandGLContext::eglConfig() const -- cgit v0.12 From 322c96eb9564f930a63be820c22b053630663880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Sun, 8 May 2011 10:53:56 +0200 Subject: Fix the wayland windowsurface so that we have stencil and depth buffer --- .../platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp index ebe4c7b..7929ccb 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp @@ -178,7 +178,7 @@ void QWaylandGLWindowSurface::resize(const QSize &size) QWindowSurface::resize(size); window()->platformWindow()->glContext()->makeCurrent(); delete mPaintDevice; - mPaintDevice = new QGLFramebufferObject(size); + mPaintDevice = new QGLFramebufferObject(size,QGLFramebufferObject::CombinedDepthStencil); } QT_END_NAMESPACE -- cgit v0.12 From 750071097f55be38dbdca1ed77064c8ed1a64f9e Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 12 May 2011 10:27:03 +0300 Subject: Symbian build failure for Armv5 1. Changed externs to Q_GUI_EXPORTs 2. ABSENTed missing exports from openGL's DEF-file Reviewed-by: Tomi Vihria --- src/gui/painting/qpainter.cpp | 2 +- src/opengl/qpaintengine_opengl.cpp | 4 ++-- src/openvg/qpaintengine_vg.cpp | 4 ++-- src/s60installs/eabi/QtOpenGLu.def | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 3cdf8fe..0a1e34e 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -692,7 +692,7 @@ void QPainterPrivate::updateInvMatrix() invMatrix = state->matrix.inverted(); } -extern bool qt_isExtendedRadialGradient(const QBrush &brush); +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush); void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) { diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 5fa9f32..58ce6f8 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -2119,7 +2119,7 @@ void QOpenGLPaintEnginePrivate::fillPath(const QPainterPath &path) updateGLMatrix(); } -extern bool qt_isExtendedRadialGradient(const QBrush &brush); +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush); static inline bool needsEmulation(Qt::BrushStyle style) { @@ -5450,7 +5450,7 @@ void QOpenGLPaintEngine::transformChanged() updateMatrix(state()->matrix); } -extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path); +Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path); void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush) { diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 68a6a0b..70e26fb 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -280,7 +280,7 @@ public: inline bool needsEmulation(const QBrush &brush) const { - extern bool qt_isExtendedRadialGradient(const QBrush &brush); + Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush); return qt_isExtendedRadialGradient(brush); } @@ -1579,7 +1579,7 @@ void QVGPaintEngine::draw(const QVectorPath &path) vgDestroyPath(vgpath); } -extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path); +Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path); void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush) { diff --git a/src/s60installs/eabi/QtOpenGLu.def b/src/s60installs/eabi/QtOpenGLu.def index 44f7306..11ac503 100644 --- a/src/s60installs/eabi/QtOpenGLu.def +++ b/src/s60installs/eabi/QtOpenGLu.def @@ -759,11 +759,11 @@ EXPORTS _ZNK14QGLPaintDevice9isFlippedEv @ 758 NONAME _ZNK16QGLWindowSurface8featuresEv @ 759 NONAME _ZNK26QGLFramebufferObjectFormat6mipmapEv @ 760 NONAME - _ZTI22QGLContextResourceBase @ 761 NONAME - _ZTI27QGLContextGroupResourceBase @ 762 NONAME - _ZTV22QGLContextResourceBase @ 763 NONAME - _ZTV27QGLContextGroupResourceBase @ 764 NONAME - _ZThn104_N20QGLTextureGlyphCacheD0Ev @ 765 NONAME - _ZThn104_N20QGLTextureGlyphCacheD1Ev @ 766 NONAME - _ZThn8_NK16QGLWindowSurface8featuresEv @ 767 NONAME + _ZTI22QGLContextResourceBase @ 761 NONAME ABSENT + _ZTI27QGLContextGroupResourceBase @ 762 NONAME ABSENT + _ZTV22QGLContextResourceBase @ 763 NONAME ABSENT + _ZTV27QGLContextGroupResourceBase @ 764 NONAME ABSENT + _ZThn104_N20QGLTextureGlyphCacheD0Ev @ 765 NONAME ABSENT + _ZThn104_N20QGLTextureGlyphCacheD1Ev @ 766 NONAME ABSENT + _ZThn8_NK16QGLWindowSurface8featuresEv @ 767 NONAME ABSENT -- cgit v0.12 From 9d0104d3da01e262d2178c864b4ba94f620eaa3b Mon Sep 17 00:00:00 2001 From: aavit Date: Tue, 31 May 2011 11:51:10 +0200 Subject: Still use midpoint rendering of aliased ellipses 37c329a removed this, but it is required to get correct fills, particularly for small radii Reviewed-by: gunnar --- src/gui/painting/qpaintengine_raster.cpp | 160 +++++++++++++++++++++++++++++++ src/gui/painting/qpaintengine_raster_p.h | 1 + 2 files changed, 161 insertions(+) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 730f6a2..71bbbb1 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -160,6 +160,10 @@ enum LineDrawMode { LineDrawIncludeLastPixel }; +static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data); + struct QRasterFloatPoint { qreal x; qreal y; @@ -3037,6 +3041,19 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect, return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend; } +inline ProcessSpans +QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, + const QSpanData *data) const +{ + Q_Q(const QRasterPaintEngine); + const QRasterPaintEngineState *s = q->state(); + + if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate) + return data->blend; + const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF()); + return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; +} + /*! \reimp */ @@ -3353,6 +3370,30 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) */ void QRasterPaintEngine::drawEllipse(const QRectF &rect) { + Q_D(QRasterPaintEngine); + QRasterPaintEngineState *s = state(); + + ensurePen(); + if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen) + || (qpen_style(s->lastPen) == Qt::NoPen)) + && !s->flags.antialiased + && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT + && !rect.isEmpty() + && s->matrix.type() <= QTransform::TxScale) // no shear + { + ensureBrush(); + const QRectF r = s->matrix.mapRect(rect); + ProcessSpans penBlend = d->getPenFunc(r, &s->penData); + ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData); + const QRect brect = QRect(int(r.x()), int(r.y()), + int_dim(r.x(), r.width()), + int_dim(r.y(), r.height())); + if (brect == r) { + drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend, + &s->penData, &s->brushData); + return; + } + } QPaintEngineEx::drawEllipse(rect); } @@ -5006,6 +5047,125 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _ adjustSpanMethods(); } +/*! + \internal + \a x and \a y is relative to the midpoint of \a rect. +*/ +static inline void drawEllipsePoints(int x, int y, int length, + const QRect &rect, + const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data) +{ + if (length == 0) + return; + + QT_FT_Span outline[4]; + const int midx = rect.x() + (rect.width() + 1) / 2; + const int midy = rect.y() + (rect.height() + 1) / 2; + + x = x + midx; + y = midy - y; + + // topleft + outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1); + outline[0].len = qMin(length, x - outline[0].x); + outline[0].y = y; + outline[0].coverage = 255; + + // topright + outline[1].x = x; + outline[1].len = length; + outline[1].y = y; + outline[1].coverage = 255; + + // bottomleft + outline[2].x = outline[0].x; + outline[2].len = outline[0].len; + outline[2].y = midy + (midy - y) - (rect.height() & 0x1); + outline[2].coverage = 255; + + // bottomright + outline[3].x = x; + outline[3].len = length; + outline[3].y = outline[2].y; + outline[3].coverage = 255; + + if (brush_func && outline[0].x + outline[0].len < outline[1].x) { + QT_FT_Span fill[2]; + + // top fill + fill[0].x = outline[0].x + outline[0].len - 1; + fill[0].len = qMax(0, outline[1].x - fill[0].x); + fill[0].y = outline[1].y; + fill[0].coverage = 255; + + // bottom fill + fill[1].x = outline[2].x + outline[2].len - 1; + fill[1].len = qMax(0, outline[3].x - fill[1].x); + fill[1].y = outline[3].y; + fill[1].coverage = 255; + + int n = (fill[0].y >= fill[1].y ? 1 : 2); + n = qt_intersect_spans(fill, n, clip); + if (n > 0) + brush_func(n, fill, brush_data); + } + if (pen_func) { + int n = (outline[1].y >= outline[2].y ? 2 : 4); + n = qt_intersect_spans(outline, n, clip); + if (n > 0) + pen_func(n, outline, pen_data); + } +} + +/*! + \internal + Draws an ellipse using the integer point midpoint algorithm. +*/ +static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data) +{ + const qreal a = qreal(rect.width()) / 2; + const qreal b = qreal(rect.height()) / 2; + qreal d = b*b - (a*a*b) + 0.25*a*a; + + int x = 0; + int y = (rect.height() + 1) / 2; + int startx = x; + + // region 1 + while (a*a*(2*y - 1) > 2*b*b*(x + 1)) { + if (d < 0) { // select E + d += b*b*(2*x + 3); + ++x; + } else { // select SE + d += b*b*(2*x + 3) + a*a*(-2*y + 2); + drawEllipsePoints(startx, y, x - startx + 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + startx = ++x; + --y; + } + } + drawEllipsePoints(startx, y, x - startx + 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + + // region 2 + d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b); + const int miny = rect.height() & 0x1; + while (y > miny) { + if (d < 0) { // select SE + d += b*b*(2*x + 2) + a*a*(-2*y + 3); + ++x; + } else { // select S + d += a*a*(-2*y + 3); + } + --y; + drawEllipsePoints(x, y, 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + } +} /*! \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 122c2b8..61cf07b 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -325,6 +325,7 @@ public: bool isUnclipped_normalized(const QRect &rect) const; bool isUnclipped(const QRect &rect, int penWidth) const; bool isUnclipped(const QRectF &rect, int penWidth) const; + ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const; ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const; ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const; -- cgit v0.12 From 4f46153bce807a5c178a60ce89c38fdd30d13f49 Mon Sep 17 00:00:00 2001 From: aavit Date: Tue, 31 May 2011 12:29:40 +0200 Subject: Fix autotest to not depend on rasterization details This test broke with 37c329a. --- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 73e5656..5ffdf4f 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -6413,6 +6413,7 @@ void tst_QGraphicsItem::boundingRegion_data() QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform() << QRegion(QRect(0, 0, 10, 10)); +#if 0 { QRegion r; r += QRect(0, 0, 6, 2); @@ -6430,6 +6431,7 @@ void tst_QGraphicsItem::boundingRegion_data() r += QRect(6, 9, 4, 1); QTest::newRow("(0, 0, 10, 10) | 1.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(1.0) << QTransform() << r; } +#endif QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform() << QRegion(QRect(0, 0, 10, 1)); QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform() -- cgit v0.12 From 43ce5bab32e0d28366317be99df5e6df70787826 Mon Sep 17 00:00:00 2001 From: aavit Date: Thu, 2 Jun 2011 15:29:11 +0200 Subject: Fix problem with cosmetic stroking of cubic beziers The new algorithm would fail if the start and end point were identical. --- src/gui/painting/qcosmeticstroker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 47a1359..cdc0978 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -663,8 +663,8 @@ void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, qreal dy = points[3].y - points[0].y; qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy)); - if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) > len || - qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) > len) { + if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len || + qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) { splitCubic(points); --level; -- cgit v0.12 From 8339121e0942e3e3b81af551a47be7b4a347608c Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Wed, 1 Jun 2011 10:50:56 +0200 Subject: Add the new 'glhypnotizer' demo. Introduce a new demo to demonstrate the usage of OpenGL from a separate thread. Reviewed-by: Samuel --- demos/demos.pro | 4 + demos/glhypnotizer/glhypnotizer.pro | 21 +++ demos/glhypnotizer/hypnotizer.qrc | 6 + demos/glhypnotizer/main.cpp | 315 +++++++++++++++++++++++++++++++++++ demos/glhypnotizer/qt-logo.png | Bin 0 -> 2493 bytes demos/glhypnotizer/spiral.svg | 100 +++++++++++ doc/src/demos/glhypnotizer.qdoc | 38 +++++ doc/src/images/glhypnotizer-demo.png | Bin 0 -> 46888 bytes 8 files changed, 484 insertions(+) create mode 100644 demos/glhypnotizer/glhypnotizer.pro create mode 100644 demos/glhypnotizer/hypnotizer.qrc create mode 100644 demos/glhypnotizer/main.cpp create mode 100644 demos/glhypnotizer/qt-logo.png create mode 100644 demos/glhypnotizer/spiral.svg create mode 100644 doc/src/demos/glhypnotizer.qdoc create mode 100644 doc/src/images/glhypnotizer-demo.png diff --git a/demos/demos.pro b/demos/demos.pro index f1d5b00..ed18446 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -44,6 +44,9 @@ wince*: SUBDIRS = \ contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles2):{ SUBDIRS += demos_boxes } +contains(QT_CONFIG, opengl):contains(QT_CONFIG, svg){ +SUBDIRS += demos_glhypnotizer +} mac* && !qpa: SUBDIRS += demos_macmainwindow wince*|symbian|embedded|x11: SUBDIRS += demos_embedded @@ -103,6 +106,7 @@ demos_browser.subdir = browser demos_boxes.subdir = boxes demos_sub-attaq.subdir = sub-attaq demos_spectrum.subdir = spectrum +demos_glhypnotizer.subdir = glhypnotizer #CONFIG += ordered !ordered { diff --git a/demos/glhypnotizer/glhypnotizer.pro b/demos/glhypnotizer/glhypnotizer.pro new file mode 100644 index 0000000..a7fdf5e --- /dev/null +++ b/demos/glhypnotizer/glhypnotizer.pro @@ -0,0 +1,21 @@ +TEMPLATE = app +CONFIG -= moc +INCLUDEPATH += . + +# Input +SOURCES += main.cpp +QT += opengl svg +RESOURCES = hypnotizer.qrc + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +# install +target.path = $$[QT_INSTALL_DEMOS]/glhypnotizer +sources.files = $$SOURCES $$HEADERS $$RESOURCES *.png *.pro *.svg +sources.path = $$[QT_INSTALL_DEMOS]/glhypnotizer +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) diff --git a/demos/glhypnotizer/hypnotizer.qrc b/demos/glhypnotizer/hypnotizer.qrc new file mode 100644 index 0000000..97ba159 --- /dev/null +++ b/demos/glhypnotizer/hypnotizer.qrc @@ -0,0 +1,6 @@ + + + qt-logo.png + spiral.svg + + \ No newline at end of file diff --git a/demos/glhypnotizer/main.cpp b/demos/glhypnotizer/main.cpp new file mode 100644 index 0000000..d6f3dc9 --- /dev/null +++ b/demos/glhypnotizer/main.cpp @@ -0,0 +1,315 @@ +#include +#include +#include + +#define NUM_SWIRLY_ITEMS 10 + +class GLPainter : public QObject +{ + Q_OBJECT +public: + GLPainter(QGLWidget *widget); + void stop(); + void resizeViewport(const QSize &size); + +public slots: + void start(); + +protected: + void timerEvent(QTimerEvent *event); + void paint(); + void initSwirlyItems(); + void updateSwirlyItems(); + void drawSuggestiveMessages(QPainter *p); + +private: + QMutex mutex; + QGLWidget *glWidget; + int viewportWidth; + int viewportHeight; + bool doRendering; + qreal rotationAngle; + bool swirlClockwise; + QSvgRenderer svgRenderer; + QPixmap logo; + QPainter::PixmapFragment swirlyItems[NUM_SWIRLY_ITEMS]; + int swirlyCounter; + int textCounter; + int messageYPos; + qreal scaleFactor; +}; + + +GLPainter::GLPainter(QGLWidget *widget) + : glWidget(widget) + , doRendering(true) + , rotationAngle(rand() % 360) + , swirlClockwise((rand() % 2) == 1) + , svgRenderer(QLatin1String(":/spiral.svg"), this) + , logo(QLatin1String(":/qt-logo.png")) +{ +} + +void GLPainter::start() +{ + glWidget->makeCurrent(); + startTimer(20); +} + +void GLPainter::stop() +{ + QMutexLocker locker(&mutex); + doRendering = false; +} + +void GLPainter::resizeViewport(const QSize &size) +{ + QMutexLocker locker(&mutex); + viewportWidth = size.width(); + viewportHeight = size.height(); + initSwirlyItems(); + textCounter = 0; + messageYPos = -1; +} + +void GLPainter::timerEvent(QTimerEvent *event) +{ + QMutexLocker locker(&mutex); + if (!doRendering) { + killTimer(event->timerId()); + QThread::currentThread()->quit(); + return; + } + updateSwirlyItems(); + paint(); +} + +void GLPainter::paint() +{ + QPainter p(glWidget); + p.fillRect(QRect(0, 0, viewportWidth, viewportHeight), Qt::white); + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + p.translate(viewportWidth / 2, viewportHeight / 2); + p.rotate(rotationAngle * (swirlClockwise ? 1 : -1)); + p.scale(svgRenderer.viewBox().width() / 200.0 * 0.65, + svgRenderer.viewBox().height() / 200.0 * 0.65); + p.translate(-viewportWidth / 2, -viewportHeight / 2); + svgRenderer.render(&p); + p.resetTransform(); + p.drawPixmapFragments(swirlyItems, NUM_SWIRLY_ITEMS, logo); + drawSuggestiveMessages(&p); + p.end(); + rotationAngle += 1.2; +} + +void GLPainter::drawSuggestiveMessages(QPainter *p) +{ + const int numSuggestiveMessages = 7; + const char *texts[numSuggestiveMessages] = {" You feel relaxed.. ", + " Let your mind wander.. ", + " Look deep into the swirls.. ", + " Even deeper.. ", + " Qt is good! ", + " Qt is good for you! ", + " You MUST use Qt! "}; + QFont font(p->font()); + font.setPointSizeF(font.pointSizeF() * viewportWidth/200.0); + p->setFont(font); + QFontMetrics fm(font); + int messageNo = textCounter/314; + if (messageNo > 6 || messageNo < 0) { + qFatal("This should not happen: %d - %d", messageNo, textCounter); + } + QLatin1String text(texts[textCounter / 314]); + qreal textWidth = fm.width(text); + int alpha = 255 * qAbs(qSin(textCounter * 0.01)); + if (messageYPos < 0 || (textCounter % 314 == 0)) { + messageYPos = qBound(fm.height(), rand() % viewportHeight, + viewportHeight - fm.height()); + } + p->setPen(QColor(255, 255, 255, alpha)); + p->setBackground(QColor(50, 50, 50, qBound(0, alpha, 50))); + p->setBackgroundMode(Qt::OpaqueMode); + p->drawText((viewportWidth / 2) - (textWidth/ 2), messageYPos, text); + ++textCounter; + if (textCounter >= (314 * numSuggestiveMessages)) + textCounter = 0; +} + +void GLPainter::initSwirlyItems() +{ + swirlyCounter = swirlClockwise ? 0 : 360; + scaleFactor = viewportWidth / 200.0; + QRectF logoRect(0, 0, logo.width(), logo.height()); + + for (int i=0; i 0 && factor <= 360) { + swirlyItems[i].x = viewportWidth / 2.0 + qSin(factor * 0.05) * (viewportWidth / 2.0) * (100.0 / factor); + swirlyItems[i].y = viewportHeight / 2.0 + qCos(factor * 0.05) * (viewportHeight / 2.0) * (100.0 / factor); + swirlyItems[i].rotation += -swirlyCounter * 0.01; + swirlyItems[i].scaleX += swirlClockwise ? -scaleFactor * 1 / 360.0 : scaleFactor * 1 / 360.0; + if (swirlClockwise) { + if (swirlyItems[i].scaleX < 0) + swirlyItems[i].scaleX = scaleFactor; + } else { + if (swirlyItems[i].scaleX > scaleFactor) + swirlyItems[i].scaleX = scaleFactor * 1 / 360.0; + } + swirlyItems[i].scaleY = swirlyItems[i].scaleX; + } else { + swirlyItems[i].scaleX = swirlyItems[i].scaleY = 0; + } + } + if (swirlClockwise) { + if (swirlyCounter > (360 + NUM_SWIRLY_ITEMS * 20)) + swirlyCounter = 0; + } else { + if (swirlyCounter < -NUM_SWIRLY_ITEMS * 20) + swirlyCounter = 360; + } +} + +class GLWidget : public QGLWidget +{ +public: + GLWidget(QWidget *parent, QGLWidget *shareWidget = 0); + ~GLWidget(); + void startRendering(); + void stopRendering(); + +protected: + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); + QSize sizeHint() const { return QSize(200, 200); } + +private: + GLPainter glPainter; + QThread glThread; +}; + +GLWidget::GLWidget(QWidget *parent, QGLWidget *share) + : QGLWidget(QGLFormat(QGL::SampleBuffers), parent, share) + , glPainter(this) + , glThread(this) +{ + setAttribute(Qt::WA_PaintOutsidePaintEvent); + setAttribute(Qt::WA_DeleteOnClose); +} + +GLWidget::~GLWidget() +{ + stopRendering(); +} + +void GLWidget::startRendering() +{ + glPainter.moveToThread(&glThread); + connect(&glThread, SIGNAL(started()), &glPainter, SLOT(start())); + glThread.start(); +} + +void GLWidget::stopRendering() +{ + glPainter.stop(); + glThread.wait(); +} + +void GLWidget::resizeEvent(QResizeEvent *event) +{ + glPainter.resizeViewport(event->size()); +} + +void GLWidget::paintEvent(QPaintEvent *) +{ + // Handled by GLPainter. +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(); + +private slots: + void newThread(); + void killThread(); + +private: + QMdiArea mdiArea; + QGLWidget shareWidget; +}; + +MainWindow::MainWindow() + : QMainWindow(0) + , mdiArea(this) + , shareWidget(this) +{ + setWindowTitle("Qt GL Hypnotizer"); + QMenu *menu = menuBar()->addMenu("&Hypnotizers"); + menu->addAction("&New hypnotizer thread", this, SLOT(newThread()), QKeySequence("Ctrl+N")); + menu->addAction("&End current hypnotizer thread", this, SLOT(killThread()), QKeySequence("Ctrl+K")); + menu->addSeparator(); + menu->addAction("E&xit", qApp, SLOT(quit()), QKeySequence("Ctrl+Q")); + + setCentralWidget(&mdiArea); + shareWidget.resize(1, 1); + newThread(); +} + +void MainWindow::newThread() +{ + static int windowCount = 1; + if (mdiArea.subWindowList().count() > 9) + return; + GLWidget *widget = new GLWidget(&mdiArea, &shareWidget); + mdiArea.addSubWindow(widget); + widget->setWindowTitle("Thread #" + QString::number(windowCount++)); + widget->show(); + widget->startRendering(); +} + +void MainWindow::killThread() +{ + delete mdiArea.activeSubWindow(); +} + +int main(int argc, char *argv[]) +{ + // Make Xlib and GLX thread safe under X11 + QApplication::setAttribute(Qt::AA_X11InitThreads); + QApplication application(argc, argv); + + // Using QPainter to draw into QGLWidgets is only supported with GL 2.0 + if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || + (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { + QMessageBox::information(0, "Qt GL Hypnotizer", + "This system does not support OpenGL 2.0 or OpenGL ES 2.0, " + "which is required for this example to work."); + return 0; + } + + MainWindow mainWindow; + mainWindow.show(); + return application.exec(); +} + +#include "main.moc" diff --git a/demos/glhypnotizer/qt-logo.png b/demos/glhypnotizer/qt-logo.png new file mode 100644 index 0000000..eaea344 Binary files /dev/null and b/demos/glhypnotizer/qt-logo.png differ diff --git a/demos/glhypnotizer/spiral.svg b/demos/glhypnotizer/spiral.svg new file mode 100644 index 0000000..ff1f047 --- /dev/null +++ b/demos/glhypnotizer/spiral.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/doc/src/demos/glhypnotizer.qdoc b/doc/src/demos/glhypnotizer.qdoc new file mode 100644 index 0000000..97b3c3b --- /dev/null +++ b/doc/src/demos/glhypnotizer.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example demos/glhypnotizer + \title GL Hypnotizer + + This demo shows how to use OpenGL from a seperate thread. + + \image glhypnotizer-demo.png + + New MDI windows can be added by pressing Ctrl-N and each new child + window renders in it's own thread. +*/ diff --git a/doc/src/images/glhypnotizer-demo.png b/doc/src/images/glhypnotizer-demo.png new file mode 100644 index 0000000..5b7a1ae Binary files /dev/null and b/doc/src/images/glhypnotizer-demo.png differ -- cgit v0.12 From 243535036078fec14bc460ccf41708ff14878797 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 1 Jun 2011 11:06:55 +0200 Subject: Refactor glyph pretransform check Move paintEngineSupportsTransformations logic from QPainter to paint engine subclasses. Simplify and consolidate checks for cached drawing (pretransformed) and path drawing (untransformed) in raster paint engine. Fix unnecessary transform when paint engines actually take the path drawing track. Fix scaling and rotation transform in raster engine for Mac. Task-number: QTBUG-19086 Change-Id: I1c0c1800a5173d3db765b9fccfd0e7a3628e3815 Reviewed-on: http://codereview.qt.nokia.com/298 Reviewed-by: Qt Sanity Bot Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit 43c0e08ba2e3487840b4063b2099bc17cdd4dce2) --- src/gui/painting/qpaintengine_mac_p.h | 2 + src/gui/painting/qpaintengine_raster.cpp | 67 +++++++++++----------- src/gui/painting/qpaintengine_raster_p.h | 2 + src/gui/painting/qpaintengineex.cpp | 10 ++++ src/gui/painting/qpaintengineex_p.h | 1 + src/gui/painting/qpainter.cpp | 36 +++++------- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 1 + src/opengl/qpaintengine_opengl_p.h | 1 + src/openvg/qpaintengine_vg_p.h | 1 + 9 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h index 3e71d6c..45a9f20 100644 --- a/src/gui/painting/qpaintengine_mac_p.h +++ b/src/gui/painting/qpaintengine_mac_p.h @@ -121,6 +121,8 @@ public: void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) { QPaintEngine::drawPolygon(points, pointCount, mode); } + bool supportsTransformations(qreal, const QTransform &) const { return true; }; + protected: friend class QMacPrintEngine; friend class QMacPrintEnginePrivate; diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 71bbbb1..a1d728c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3062,11 +3062,8 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensurePen(); ensureState(); - QRasterPaintEngineState *s = state(); - QFontEngine *fontEngine = textItem->fontEngine(); - const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) < 64 * 64) { + if (!supportsTransformations(fontEngine)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else { @@ -3094,36 +3091,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte #if defined (Q_WS_WIN) || defined(Q_WS_MAC) - bool drawCached = true; - - if (s->matrix.type() >= QTransform::TxProject) - drawCached = false; - - // don't try to cache huge fonts - const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64) - drawCached = false; - - // ### Remove the TestFontEngine and Box engine crap, in these - // ### cases we should delegate painting to the font engine - // ### directly... - -#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) - QFontEngine::Type fontEngineType = ti.fontEngine->type(); - // qDebug() << "type" << fontEngineType << s->matrix.type(); - if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate) - || (s->matrix.type() <= QTransform::TxTranslate - && (fontEngineType == QFontEngine::TestFontEngine - || fontEngineType == QFontEngine::Box))) { - drawCached = false; - } -#else - if (s->matrix.type() > QTransform::TxTranslate) - drawCached = false; -#endif - if (drawCached) { - QRasterPaintEngineState *s = state(); - + if (!supportsTransformations(ti.fontEngine)) { QVarLengthArray positions; QVarLengthArray glyphs; @@ -3444,6 +3412,37 @@ void QRasterPaintEngine::releaseDC(HDC) const #endif +bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const +{ + const QTransform &m = state()->matrix; +#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) + QFontEngine::Type fontEngineType = ti.fontEngine->type(); + if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && m.type() > QTransform::TxTranslate) + || (m.type() <= QTransform::TxTranslate + && (fontEngineType == QFontEngine::TestFontEngine + || fontEngineType == QFontEngine::Box))) { + return true; + } +#endif + return supportsTransformations(fontEngine->fontDef.pixelSize, m); +} + +bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const +{ +#if defined(Q_WS_MAC) + // Mac font engines don't support scaling and rotation + if (m.type() > QTransform::TxTranslate) +#else + if (m.type() >= QTransform::TxProject) +#endif + return true; + + if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64) + return true; + + return false; +} + /*! \internal */ diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 61cf07b..d65e922 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -246,6 +246,8 @@ public: virtual void drawBufferSpan(const uint *buffer, int bufsize, int x, int y, int length, uint const_alpha); #endif + bool supportsTransformations(const QFontEngine *fontEngine) const; + bool supportsTransformations(qreal pixelSize, const QTransform &m) const; protected: QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 304e5fc..b1dc780 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1093,4 +1093,14 @@ void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem) } } +bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &m) const +{ + Q_UNUSED(pixelSize); + + if (!m.isAffine()) + return true; + + return false; +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 7d57eee..9cfda74 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -227,6 +227,7 @@ public: IsEmulationEngine = 0x02 // If set, this object is a QEmulationEngine. }; virtual uint flags() const {return 0;} + virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const; protected: QPaintEngineEx(QPaintEngineExPrivate &data); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 0a1e34e..7ec6d6a 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -152,14 +152,6 @@ static inline uint line_emulation(uint emulation) | QPaintEngine_OpaqueBackground); } -static bool qt_paintengine_supports_transformations(QPaintEngine::Type type) -{ - return type == QPaintEngine::OpenGL2 - || type == QPaintEngine::OpenVG - || type == QPaintEngine::OpenGL - || type == QPaintEngine::CoreGraphics; -} - #ifndef QT_NO_DEBUG static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false) { @@ -5815,20 +5807,19 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun) int count = qMin(glyphIndexes.size(), glyphPositions.size()); QVarLengthArray fixedPointPositions(count); - bool paintEngineSupportsTransformations = - d->extended != 0 - ? qt_paintengine_supports_transformations(d->extended->type()) - : qt_paintengine_supports_transformations(d->engine->type()); - - // If the matrix is not affine, the paint engine will fall back to - // drawing the glyphs as paths, which in turn means we should not - // preprocess the glyph positions - if (!d->state->matrix.isAffine()) - paintEngineSupportsTransformations = true; + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + bool supportsTransformations; + if (d->extended != 0) { + supportsTransformations = d->extended->supportsTransformations(fontD->fontEngine->fontDef.pixelSize, + d->state->matrix); + } else { + supportsTransformations = d->engine->type() == QPaintEngine::CoreGraphics + || d->state->matrix.isAffine(); + } for (int i=0; istate->transform().map(processedPosition); fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); } @@ -6004,11 +5995,12 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText return; } - bool paintEngineSupportsTransformations = qt_paintengine_supports_transformations(d->extended->type()); - if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) { + bool supportsTransformations = d->extended->supportsTransformations(staticText_d->font.pixelSize(), + d->state->matrix); + if (supportsTransformations && !staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = true; staticText_d->needsRelayout = true; - } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) { + } else if (!supportsTransformations && staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = false; staticText_d->needsRelayout = true; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index f7ec5f5..a97223d 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -158,6 +158,7 @@ public: void setRenderTextActive(bool); bool isNativePaintingActive() const; + bool supportsTransformations(qreal, const QTransform &) const { return true; } private: Q_DISABLE_COPY(QGL2PaintEngineEx) }; diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h index 8f12be4..aaca48a 100644 --- a/src/opengl/qpaintengine_opengl_p.h +++ b/src/opengl/qpaintengine_opengl_p.h @@ -143,6 +143,7 @@ public: Qt::HANDLE handle() const; #endif inline Type type() const { return QPaintEngine::OpenGL; } + bool supportsTransformations(qreal, const QTransform &) const { return true; } private: void drawPolyInternal(const QPolygonF &pa, bool close = true); diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index 1e9103b..2aba5a2 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -159,6 +159,7 @@ public: QVGPaintEnginePrivate *vgPrivate() { Q_D(QVGPaintEngine); return d; } void fillRegion(const QRegion& region, const QColor& color, const QSize& surfaceSize); + bool supportsTransformations(qreal, const QTransform &) const { return true; } protected: QVGPaintEngine(QVGPaintEnginePrivate &data); -- cgit v0.12 From d2d6f3963d11e969bf0fe0ff35064be5455f80c5 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 3 Jun 2011 11:56:27 +0200 Subject: Fix Windows build --- src/gui/painting/qpaintengine_raster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index a1d728c..7161fe3 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3416,8 +3416,8 @@ bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) { const QTransform &m = state()->matrix; #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) - QFontEngine::Type fontEngineType = ti.fontEngine->type(); - if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && m.type() > QTransform::TxTranslate) + QFontEngine::Type fontEngineType = fontEngine->type(); + if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate) || (m.type() <= QTransform::TxTranslate && (fontEngineType == QFontEngine::TestFontEngine || fontEngineType == QFontEngine::Box))) { -- cgit v0.12 From 81da1a8f774ec258f45549734e84770655a7c8e8 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 3 Jun 2011 13:31:05 +0200 Subject: Add basic static text drawing capability to lance Task-number: QTBUG-17514 Change-Id: Ife7cd8f940424d805f634ca190bcbf6fd83d8682 Reviewed-on: http://codereview.qt.nokia.com/321 Reviewed-by: Qt Sanity Bot Reviewed-by: aavit (cherry picked from commit ce041a6516bfb0d9bd9ee1707605b478e1c9171a) --- tests/arthur/common/paintcommands.cpp | 20 +++++ tests/arthur/common/paintcommands.h | 1 + tests/auto/lancelot/scripts/statictext.qps | 122 +++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 tests/auto/lancelot/scripts/statictext.qps diff --git a/tests/arthur/common/paintcommands.cpp b/tests/arthur/common/paintcommands.cpp index 9273142..7b10da0 100644 --- a/tests/arthur/common/paintcommands.cpp +++ b/tests/arthur/common/paintcommands.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #ifdef QT3_SUPPORT #include @@ -464,6 +465,10 @@ void PaintCommands::staticInit() "^drawText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$", "drawText ", "drawText 10 10 \"my text\""); + DECL_PAINTCOMMAND("drawStaticText", command_drawStaticText, + "^drawStaticText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$", + "drawStaticText ", + "drawStaticText 10 10 \"my text\""); DECL_PAINTCOMMAND("drawTiledPixmap", command_drawTiledPixmap, "^drawTiledPixmap\\s+([\\w.:\\/]*)" "\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)\\s*(-?\\w*)" @@ -1404,6 +1409,21 @@ void PaintCommands::command_drawText(QRegExp re) m_painter->drawText(x, y, txt); } +void PaintCommands::command_drawStaticText(QRegExp re) +{ + if (!m_shouldDrawText) + return; + QStringList caps = re.capturedTexts(); + int x = convertToInt(caps.at(1)); + int y = convertToInt(caps.at(2)); + QString txt = caps.at(3); + + if (m_verboseMode) + printf(" -(lance) drawStaticText(%d, %d, %s)\n", x, y, qPrintable(txt)); + + m_painter->drawStaticText(x, y, QStaticText(txt)); +} + /***************************************************************************************************/ void PaintCommands::command_noop(QRegExp) { diff --git a/tests/arthur/common/paintcommands.h b/tests/arthur/common/paintcommands.h index 08c0e25..d0a2b98 100644 --- a/tests/arthur/common/paintcommands.h +++ b/tests/arthur/common/paintcommands.h @@ -209,6 +209,7 @@ private: void command_drawRoundedRect(QRegExp re); void command_drawRoundRect(QRegExp re); void command_drawText(QRegExp re); + void command_drawStaticText(QRegExp re); void command_drawTiledPixmap(QRegExp re); void command_path_addEllipse(QRegExp re); void command_path_addPolygon(QRegExp re); diff --git a/tests/auto/lancelot/scripts/statictext.qps b/tests/auto/lancelot/scripts/statictext.qps new file mode 100644 index 0000000..b62b623 --- /dev/null +++ b/tests/auto/lancelot/scripts/statictext.qps @@ -0,0 +1,122 @@ +drawStaticText -5 5 "Text that is drawn outside the bounds..." + +translate 20 20 +begin_block text_drawing +save + setFont "sansserif" 10 normal + drawStaticText 0 20 "sansserif 10pt, normal" + + setFont "sansserif" 12 normal + drawStaticText 0 40 "sansserif 12pt, normal" + + setFont "sansserif" 10 bold + drawStaticText 0 60 "sansserif 12pt, bold" + + setFont "sansserif" 10 bold italic + drawStaticText 0 80 "sansserif 10pt, bold italic" + + + translate 0 100 + setPen #7fff0000 + + setFont "sansserif" 10 normal + drawStaticText 0 20 "alpha sansserif 10pt, normal" + + setFont "sansserif" 12 normal + drawStaticText 0 40 "alpha sansserif 12pt, normal" + + setFont "sansserif" 10 bold + drawStaticText 0 60 "alpha sansserif 12pt, bold" + + setFont "sansserif" 10 bold italic + drawStaticText 0 80 "alpha sansserif 10pt, bold italic" + + + translate 0 100 + setPen black + save + scale 0.9 0.9 + + setFont "sansserif" 10 normal + drawStaticText 0 20 "scaled sansserif 10pt, normal" + + setFont "sansserif" 12 normal + drawStaticText 0 40 "scaled sansserif 12pt, normal" + + setFont "sansserif" 10 bold + drawStaticText 0 60 "scaled sansserif 12pt, bold" + + setFont "sansserif" 10 bold italic + drawStaticText 0 80 "scaled sansserif 10pt, bold italic" + restore + + translate 0 100 + setPen black + save + translate 200 90 + rotate 185 + + setFont "sansserif" 10 normal + drawStaticText 0 20 "scaled sansserif 10pt, normal" + + setFont "sansserif" 12 normal + drawStaticText 0 40 "scaled sansserif 12pt, normal" + + setFont "sansserif" 10 bold + drawStaticText 0 60 "scaled sansserif 12pt, bold" + + setFont "sansserif" 10 bold italic + drawStaticText 0 80 "scaled sansserif 10pt, bold italic" + restore + + translate 0 100 + gradient_appendStop 0 red + gradient_appendStop 0.5 #00ff00 + gradient_appendStop 1 blue + gradient_setLinear 0 0 200 0 + setPen brush + + setFont "sansserif" 10 normal + drawStaticText 0 0 "gradient sansserif 10pt, normal" + + setFont "sansserif" 12 normal + drawStaticText 0 20 "gradient sansserif 12pt, normal" + + setFont "sansserif" 10 bold + drawStaticText 0 40 "gradient sansserif 12pt, bold" + + setFont "sansserif" 10 bold italic + drawStaticText 0 60 "gradient sansserif 10pt, bold italic" +restore +end_block + +translate 250 0 +drawStaticText 25 520 "clipped to rectangle" +save + setPen #3f000000 + setBrush nobrush + drawRect 20 0 100 500 + setClipRect 20 0 100 500 + setPen black + repeat_block text_drawing +restore + +translate 150 0 +drawStaticText 25 520 "clipped to path" +save + path_moveTo clip 20 0 + path_cubicTo clip 0 200 40 400 20 400 + path_lineTo clip 30 500 + path_lineTo clip 30 0 + path_lineTo clip 40 0 + path_lineTo clip 40 500 + path_lineTo clip 120 500 + path_lineTo clip 120 0 + path_lineTo clip 20 0 + setPen #3f000000 + setBrush nobrush + drawPath clip + setClipPath clip + setPen black + repeat_block text_drawing +restore -- cgit v0.12 From 29ebd2ce78eb01a130470b8e5fe776efe130bdd8 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Fri, 3 Jun 2011 16:12:23 +0200 Subject: Add missing license header. Reviewed-by: aavit --- demos/glhypnotizer/main.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/demos/glhypnotizer/main.cpp b/demos/glhypnotizer/main.cpp index d6f3dc9..cc1482d 100644 --- a/demos/glhypnotizer/main.cpp +++ b/demos/glhypnotizer/main.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + #include #include #include -- cgit v0.12 From 33616d404d4f3eaafad78e4602a4e620a012a660 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 3 Jun 2011 16:08:54 +0200 Subject: Correct QStaticText tests after recent changes Raster engine on Mac now correctly handles transformation, so no need to XFAIL anymore. Also fixes a drawStaticText origin mistake, the y origin should be the top left point rather than the baseline. Change-Id: I6058e7099b336d9d5a6586344a07be3c7d76fb64 Reviewed-on: http://codereview.qt.nokia.com/329 Reviewed-by: Qt Sanity Bot Reviewed-by: Jiang Jiang (cherry picked from commit ea0e38c0ddb687f7873e0937e1b7130f1588c3d6) --- tests/auto/qstatictext/tst_qstatictext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 0c4857a..a924119 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -361,7 +361,7 @@ bool tst_QStaticText::supportsTransformations() const QPaintEngine::Type type = engine->type(); if (type == QPaintEngine::OpenGL -#if !defined(Q_WS_WIN) && !defined(Q_WS_X11) +#if !defined(Q_WS_WIN) && !defined(Q_WS_X11) && !defined(Q_WS_MAC) || type == QPaintEngine::Raster #endif ) @@ -601,7 +601,7 @@ void tst_QStaticText::setPenPlainText() QStaticText staticText("XXXXX"); staticText.setTextFormat(Qt::PlainText); - p.drawStaticText(0, fm.ascent(), staticText); + p.drawStaticText(0, 0, staticText); } QImage img = image.toImage(); -- cgit v0.12 From 278c2b360aba87db2d1e5a2d3e14de7260d8a16e Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Fri, 3 Jun 2011 16:03:00 +0200 Subject: Correct antialias disabling logic for Core Text We should always turn antialias off when QFont::NoAntialias being passed in styleStrategy. That corrects some QStaticText tests. Change-Id: Iaffc5f3bb7f501dcb648cab41a8b6ffcf93f90ae Reviewed-on: http://codereview.qt.nokia.com/328 Reviewed-by: Qt Sanity Bot Reviewed-by: Jiang Jiang (cherry picked from commit c25495dba7eff32b66119737552905787e97e665) --- src/gui/text/qfontengine_coretext.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index 982c271..75b4e1f 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -745,9 +745,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition 8, im.bytesPerLine(), colorspace, cgflags); CGContextSetFontSize(ctx, fontDef.pixelSize); - CGContextSetShouldAntialias(ctx, aa || - (fontDef.pointSize > qt_antialiasing_threshold - && !(fontDef.styleStrategy & QFont::NoAntialias))); + CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > qt_antialiasing_threshold) + && !(fontDef.styleStrategy & QFont::NoAntialias)); CGContextSetShouldSmoothFonts(ctx, aa); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0); -- cgit v0.12 From 86d88c5b719fd3d50336d9d8e7127b8045ee82ae Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 10 May 2011 15:08:29 +0200 Subject: Add function QGlyphRun::setRawData() To provide an optimized way of constructing QGlyphRun objects with no copying or allocation, we add function setRawData() (naming inspired by QByteArray::setRawData()). Data retrieved from QRawFont can be passed directly into this. The logic is now that the data pointers in QGlyphRunPrivate should always point to the current valid data and is what will be used in comparisons and drawing calls. The vectors are optimizations to avoid unnecessary copying if the user wants to use the QVector based API (which makes it easier to manage the memory.) This reflected in the functions that return QVectors, which will return the stored vector if and only if it is identical to the current pointer. Otherwise we will have to copy the memory. The internal addition operators in QGlyphRun have been removed since they really provide no real optimization and have an unclear definition if the two glyph runs are based on different fonts. Reviewed-by: Jiang Jiang --- src/gui/painting/qpainter.cpp | 15 +++-- src/gui/painting/qpainter_p.h | 2 +- src/gui/text/qglyphrun.cpp | 108 ++++++++++++++++++++------------- src/gui/text/qglyphrun.h | 4 ++ src/gui/text/qglyphrun_p.h | 19 ++++++ src/gui/text/qtextlayout.cpp | 16 ++++- tests/auto/qglyphrun/tst_qglyphrun.cpp | 79 ++++++++++++++++++++++++ 7 files changed, 190 insertions(+), 53 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index d2b35c8..1bd9303 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5801,10 +5801,12 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun) if (!font.isValid()) return; - QVector glyphIndexes = glyphRun.glyphIndexes(); - QVector glyphPositions = glyphRun.positions(); + QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun); - int count = qMin(glyphIndexes.size(), glyphPositions.size()); + const quint32 *glyphIndexes = glyphRun_d->glyphIndexData; + const QPointF *glyphPositions = glyphRun_d->glyphPositionData; + + int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize); QVarLengthArray fixedPointPositions(count); QRawFontPrivate *fontD = QRawFontPrivate::get(font); @@ -5818,17 +5820,18 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun) } for (int i=0; istate->transform().map(processedPosition); fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); } - d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphRun.overline(), + d->drawGlyphs(glyphIndexes, fixedPointPositions.data(), count, font, glyphRun.overline(), glyphRun.underline(), glyphRun.strikeOut()); } -void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount, +void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positions, + int glyphCount, const QRawFont &font, bool overline, bool underline, bool strikeOut) { diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 35cdf86..79d4b4b 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -232,7 +232,7 @@ public: void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); #if !defined(QT_NO_RAWFONT) - void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, + void drawGlyphs(const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, const QRawFont &font, bool overline = false, bool underline = false, bool strikeOut = false); #endif diff --git a/src/gui/text/qglyphrun.cpp b/src/gui/text/qglyphrun.cpp index 05e3b6b..2865d91 100644 --- a/src/gui/text/qglyphrun.cpp +++ b/src/gui/text/qglyphrun.cpp @@ -132,13 +132,27 @@ QGlyphRun &QGlyphRun::operator=(const QGlyphRun &other) */ bool QGlyphRun::operator==(const QGlyphRun &other) const { - return ((d == other.d) - || (d->glyphIndexes == other.d->glyphIndexes - && d->glyphPositions == other.d->glyphPositions - && d->overline == other.d->overline - && d->underline == other.d->underline - && d->strikeOut == other.d->strikeOut - && d->rawFont == other.d->rawFont)); + if (d == other.d) + return true; + + if ((d->glyphIndexDataSize != other.d->glyphIndexDataSize) + || (d->glyphPositionDataSize != other.d->glyphPositionDataSize)) { + return false; + } + + for (int i=0; iglyphIndexDataSize, d->glyphPositionDataSize); ++i) { + if (i < d->glyphIndexDataSize && d->glyphIndexData[i] != other.d->glyphIndexData[i]) + return false; + + if (i < d->glyphPositionDataSize && d->glyphPositionData[i] != other.d->glyphPositionData[i]) + return false; + } + + + return (d->overline == other.d->overline + && d->underline == other.d->underline + && d->strikeOut == other.d->strikeOut + && d->rawFont == other.d->rawFont); } /*! @@ -151,36 +165,6 @@ bool QGlyphRun::operator!=(const QGlyphRun &other) const } /*! - \internal - - Adds together the lists of glyph indexes and positions in \a other and this QGlyphRun - object and returns the result. The font in the returned QGlyphRun will be the same as in - this QGlyphRun object. -*/ -QGlyphRun QGlyphRun::operator+(const QGlyphRun &other) const -{ - QGlyphRun ret(*this); - ret += other; - return ret; -} - -/*! - \internal - - Appends the glyph indexes and positions in \a other to this QGlyphRun object and returns - a reference to the current object. -*/ -QGlyphRun &QGlyphRun::operator+=(const QGlyphRun &other) -{ - detach(); - - d->glyphIndexes += other.d->glyphIndexes; - d->glyphPositions += other.d->glyphPositions; - - return *this; -} - -/*! Returns the font selected for this QGlyphRun object. \sa setRawFont() @@ -208,7 +192,13 @@ void QGlyphRun::setRawFont(const QRawFont &rawFont) */ QVector QGlyphRun::glyphIndexes() const { - return d->glyphIndexes; + if (d->glyphIndexes.constData() == d->glyphIndexData) { + return d->glyphIndexes; + } else { + QVector indexes(d->glyphIndexDataSize); + qMemCopy(indexes.data(), d->glyphIndexData, d->glyphIndexDataSize * sizeof(quint32)); + return indexes; + } } /*! @@ -218,7 +208,9 @@ QVector QGlyphRun::glyphIndexes() const void QGlyphRun::setGlyphIndexes(const QVector &glyphIndexes) { detach(); - d->glyphIndexes = glyphIndexes; + d->glyphIndexes = glyphIndexes; // Keep a reference to the QVector to avoid copying + d->glyphIndexData = glyphIndexes.constData(); + d->glyphIndexDataSize = glyphIndexes.size(); } /*! @@ -226,7 +218,14 @@ void QGlyphRun::setGlyphIndexes(const QVector &glyphIndexes) */ QVector QGlyphRun::positions() const { - return d->glyphPositions; + if (d->glyphPositions.constData() == d->glyphPositionData) { + return d->glyphPositions; + } else { + QVector glyphPositions(d->glyphPositionDataSize); + qMemCopy(glyphPositions.data(), d->glyphPositionData, + d->glyphPositionDataSize * sizeof(QPointF)); + return glyphPositions; + } } /*! @@ -236,7 +235,9 @@ QVector QGlyphRun::positions() const void QGlyphRun::setPositions(const QVector &positions) { detach(); - d->glyphPositions = positions; + d->glyphPositions = positions; // Keep a reference to the vector to avoid copying + d->glyphPositionData = positions.constData(); + d->glyphPositionDataSize = positions.size(); } /*! @@ -245,12 +246,33 @@ void QGlyphRun::setPositions(const QVector &positions) void QGlyphRun::clear() { detach(); - d->glyphPositions = QVector(); - d->glyphIndexes = QVector(); d->rawFont = QRawFont(); d->strikeOut = false; d->overline = false; d->underline = false; + + setPositions(QVector()); + setGlyphIndexes(QVector()); +} + +/*! + Sets the glyph indexes and positions of this QGlyphRun to use the first \a size + elements in the arrays \a glyphIndexArray and \a glyphPositionArray. The data is + \e not copied. The caller must guarantee that the arrays are not deleted as long + as this QGlyphRun and any copies of it exists. + + \sa setGlyphIndexes(), setPositions() +*/ +void QGlyphRun::setRawData(const quint32 *glyphIndexArray, const QPointF *glyphPositionArray, + int size) +{ + detach(); + d->glyphIndexes.clear(); + d->glyphPositions.clear(); + + d->glyphIndexData = glyphIndexArray; + d->glyphPositionData = glyphPositionArray; + d->glyphIndexDataSize = d->glyphPositionDataSize = size; } /*! diff --git a/src/gui/text/qglyphrun.h b/src/gui/text/qglyphrun.h index e43f1ef..cf407a8 100644 --- a/src/gui/text/qglyphrun.h +++ b/src/gui/text/qglyphrun.h @@ -66,6 +66,10 @@ public: QRawFont rawFont() const; void setRawFont(const QRawFont &rawFont); + void setRawData(const quint32 *glyphIndexArray, + const QPointF *glyphPositionArray, + int size); + QVector glyphIndexes() const; void setGlyphIndexes(const QVector &glyphIndexes); diff --git a/src/gui/text/qglyphrun_p.h b/src/gui/text/qglyphrun_p.h index 533679d..1cb63b2 100644 --- a/src/gui/text/qglyphrun_p.h +++ b/src/gui/text/qglyphrun_p.h @@ -71,6 +71,10 @@ public: : overline(false) , underline(false) , strikeOut(false) + , glyphIndexData(glyphIndexes.constData()) + , glyphIndexDataSize(0) + , glyphPositionData(glyphPositions.constData()) + , glyphPositionDataSize(0) { } @@ -82,6 +86,10 @@ public: , overline(other.overline) , underline(other.underline) , strikeOut(other.strikeOut) + , glyphIndexData(other.glyphIndexData) + , glyphIndexDataSize(other.glyphIndexDataSize) + , glyphPositionData(other.glyphPositionData) + , glyphPositionDataSize(other.glyphPositionDataSize) { } @@ -89,6 +97,17 @@ public: QVector glyphPositions; QRawFont rawFont; + const quint32 *glyphIndexData; + int glyphIndexDataSize; + + const QPointF *glyphPositionData; + int glyphPositionDataSize; + + static QGlyphRunPrivate *get(const QGlyphRun &glyphRun) + { + return glyphRun.d.data(); + } + uint overline : 1; uint underline : 1; uint strikeOut : 1; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 7bc87ee..203886b 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2233,10 +2233,20 @@ QList QTextLine::glyphs(int from, int length) const glyphIndexes.setRawFont(font); QPair key(fontEngine, int(flags)); - if (!glyphsHash.contains(key)) + if (!glyphsHash.contains(key)) { glyphsHash.insert(key, glyphIndexes); - else - glyphsHash[key] += glyphIndexes; + } else { + QGlyphRun &glyphRun = glyphsHash[key]; + + QVector indexes = glyphRun.glyphIndexes(); + QVector positions = glyphRun.positions(); + + indexes += glyphIndexes.glyphIndexes(); + positions += glyphIndexes.positions(); + + glyphRun.setGlyphIndexes(indexes); + glyphRun.setPositions(positions); + } } } diff --git a/tests/auto/qglyphrun/tst_qglyphrun.cpp b/tests/auto/qglyphrun/tst_qglyphrun.cpp index 3ea84e3..a18a2ac 100644 --- a/tests/auto/qglyphrun/tst_qglyphrun.cpp +++ b/tests/auto/qglyphrun/tst_qglyphrun.cpp @@ -72,6 +72,8 @@ private slots: void drawUnderlinedText(); void drawRightToLeft(); void detach(); + void setRawData(); + void setRawDataAndGetAsVector(); private: int m_testFontId; @@ -284,6 +286,83 @@ void tst_QGlyphRun::drawExistingGlyphs() QCOMPARE(textLayoutDraw, drawGlyphs); } +void tst_QGlyphRun::setRawData() +{ + QGlyphRun glyphRun; + glyphRun.setRawFont(QRawFont::fromFont(m_testFont)); + glyphRun.setGlyphIndexes(QVector() << 2 << 2 << 2); + glyphRun.setPositions(QVector() << QPointF(2, 3) << QPointF(20, 3) << QPointF(10, 20)); + + QPixmap baseline(100, 50); + baseline.fill(Qt::white); + { + QPainter p(&baseline); + p.drawGlyphRun(QPointF(3, 2), glyphRun); + } + + QGlyphRun baselineCopied = glyphRun; + + quint32 glyphIndexArray[3] = { 2, 2, 2 }; + QPointF glyphPositionArray[3] = { QPointF(2, 3), QPointF(20, 3), QPointF(10, 20) }; + + glyphRun.setRawData(glyphIndexArray, glyphPositionArray, 3); + + QPixmap rawDataGlyphs(100, 50); + rawDataGlyphs.fill(Qt::white); + { + QPainter p(&rawDataGlyphs); + p.drawGlyphRun(QPointF(3, 2), glyphRun); + } + + quint32 otherGlyphIndexArray[1] = { 2 }; + QPointF otherGlyphPositionArray[1] = { QPointF(2, 3) }; + + glyphRun.setRawData(otherGlyphIndexArray, otherGlyphPositionArray, 1); + + QPixmap baselineCopiedPixmap(100, 50); + baselineCopiedPixmap.fill(Qt::white); + { + QPainter p(&baselineCopiedPixmap); + p.drawGlyphRun(QPointF(3, 2), baselineCopied); + } + +#if defined(DEBUG_SAVE_IMAGE) + baseline.save("setRawData_baseline.png"); + rawDataGlyphs.save("setRawData_rawDataGlyphs.png"); + baselineCopiedPixmap.save("setRawData_baselineCopiedPixmap.png"); +#endif + + QCOMPARE(rawDataGlyphs, baseline); + QCOMPARE(baselineCopiedPixmap, baseline); +} + +void tst_QGlyphRun::setRawDataAndGetAsVector() +{ + QVector glyphIndexArray; + glyphIndexArray << 3 << 2 << 1 << 4; + + QVector glyphPositionArray; + glyphPositionArray << QPointF(1, 2) << QPointF(3, 4) << QPointF(5, 6) << QPointF(7, 8); + + QGlyphRun glyphRun; + glyphRun.setRawData(glyphIndexArray.constData(), glyphPositionArray.constData(), 4); + + QVector glyphIndexes = glyphRun.glyphIndexes(); + QVector glyphPositions = glyphRun.positions(); + + QCOMPARE(glyphIndexes.size(), 4); + QCOMPARE(glyphPositions.size(), 4); + + QCOMPARE(glyphIndexes, glyphIndexArray); + QCOMPARE(glyphPositions, glyphPositionArray); + + QGlyphRun otherGlyphRun; + otherGlyphRun.setGlyphIndexes(glyphIndexArray); + otherGlyphRun.setPositions(glyphPositionArray); + + QCOMPARE(glyphRun, otherGlyphRun); +} + void tst_QGlyphRun::drawNonExistentGlyphs() { QVector glyphIndexes; -- cgit v0.12 From f5a63feb8953799de7e787f333575ee37fae8a3f Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Wed, 1 Jun 2011 17:13:51 +1000 Subject: Fixed compile of tst_qscriptextensionplugin on some Windows configurations The debug and release versions of staticplugin are qmake'd with the same destination directory. This causes the generated staticplugin .prl file to always refer to the debug versions of Qt libraries, even if Qt was configured with -release. The .prl mechanism is not useful for this test, so simply disable it to solve the problem. Reviewed-by: ckamm --- tests/auto/qscriptextensionplugin/staticplugin/staticplugin.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qscriptextensionplugin/staticplugin/staticplugin.pro b/tests/auto/qscriptextensionplugin/staticplugin/staticplugin.pro index a003338..65c4e8f 100644 --- a/tests/auto/qscriptextensionplugin/staticplugin/staticplugin.pro +++ b/tests/auto/qscriptextensionplugin/staticplugin/staticplugin.pro @@ -1,5 +1,6 @@ TEMPLATE = lib CONFIG += static plugin +CONFIG -= create_prl # not needed, and complicates debug/release SOURCES = staticplugin.cpp RESOURCES = staticplugin.qrc QT = core script -- cgit v0.12 From 00898f5df8cf885f0080cd8e13ba435a36758df3 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 8 Jun 2011 09:58:37 +0200 Subject: Revert 36e01e69 The way we handle glyph cache in QFontEngineFT has changed, the memory leak fix should not be applied to 4.8. Reviewed-by: Eskil --- src/gui/text/qfontengine_ft.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index f514942..776615c 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1751,7 +1751,6 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe } else { glyphSet = &defaultGlyphSet; } - bool needsDelete = false; Glyph * g = glyphSet->getGlyph(glyph); if (!g || g->format != format) { face = lockFace(); @@ -1759,7 +1758,6 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m); freetype->matrix = m; g = loadGlyph(glyphSet, glyph, subPixelPosition, format); - needsDelete = true; } if (g) { @@ -1768,8 +1766,6 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe overall.width = g->width; overall.height = g->height; overall.xoff = g->advance; - if (needsDelete) - delete g; } else { int left = FLOOR(face->glyph->metrics.horiBearingX); int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width); -- cgit v0.12 From 74a1135341783449970d579b273d00c837ac14b0 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 8 Jun 2011 10:11:10 +0200 Subject: Reorder member varibles in QGlyphRunPrivate to eliminate warning Reviewed-by: Eskil --- src/gui/text/qglyphrun_p.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qglyphrun_p.h b/src/gui/text/qglyphrun_p.h index 1cb63b2..a7745e6 100644 --- a/src/gui/text/qglyphrun_p.h +++ b/src/gui/text/qglyphrun_p.h @@ -97,6 +97,10 @@ public: QVector glyphPositions; QRawFont rawFont; + uint overline : 1; + uint underline : 1; + uint strikeOut : 1; + const quint32 *glyphIndexData; int glyphIndexDataSize; @@ -107,10 +111,6 @@ public: { return glyphRun.d.data(); } - - uint overline : 1; - uint underline : 1; - uint strikeOut : 1; }; QT_END_NAMESPACE -- cgit v0.12 From 5ce3fbb67b79c3732fd47b296ef9421398ca520c Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Sat, 4 Jun 2011 15:53:49 +0200 Subject: Fix warning in qtextengine compilation enableHarfbuzz() should only be defined on Mac. Reviewed-by: Eskil --- src/gui/text/qtextengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index ad4f6d3..e8e6c98 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -856,7 +856,7 @@ void QTextEngine::shapeLine(const QScriptLine &line) } } -#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) && defined(Q_WS_MAC) static bool enableHarfBuzz() { static enum { Yes, No, Unknown } status = Unknown; -- cgit v0.12 From 5a598afa3f1928e9ad18257e2fa48fe3d5739917 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Sat, 4 Jun 2011 17:47:13 +0200 Subject: Fix compile when configure with no fontconfig support Task-number: QTBUG-19716 Reviewed-by: Eskil --- src/gui/text/qrawfont_ft.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index e8c10a5..db60459 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -46,7 +46,7 @@ #include "qrawfont_p.h" #include "qfontengine_ft_p.h" -#if defined(Q_WS_X11) +#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) # include "qfontengine_x11_p.h" #endif @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QFontEngineFTRawFont -#if defined(Q_WS_X11) +#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) : public QFontEngineX11FT #else : public QFontEngineFT @@ -63,7 +63,7 @@ class QFontEngineFTRawFont { public: QFontEngineFTRawFont(const QFontDef &fontDef) -#if defined(Q_WS_X11) +#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) : QFontEngineX11FT(fontDef) #else : QFontEngineFT(fontDef) -- cgit v0.12