Commit 9e797cf9 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

[scene] Introduce helpers for mapping between different coordinate spaces

We currently deal with three distinct coordinate spaces - the window
pixmap coordinate space, the window coordinate space, and the buffer
pixel coordinate space.

This change introduces a couple of helper methods to make it easier
to map points from the window pixmap space to the other two spaces.

The main motivation behind the new helpers is to break the direct
relationship between the surface-local coordinates and buffer pixel
coordinates for wayland surfaces.
parent fe83cbf0
......@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "scene_qpainter.h"
// KWin
#include "x11client.h"
#include "abstract_client.h"
#include "composite.h"
#include "cursor.h"
#include "deleted.h"
......@@ -228,37 +228,6 @@ SceneQPainter::Window::~Window()
{
}
static void paintSubSurface(QPainter *painter, const QPoint &pos, QPainterWindowPixmap *pixmap)
{
QPoint p = pos;
if (!pixmap->subSurface().isNull()) {
p += pixmap->subSurface()->position();
}
painter->drawImage(QRect(pos, pixmap->size()), pixmap->image());
const auto &children = pixmap->children();
for (auto it = children.begin(); it != children.end(); ++it) {
auto pixmap = static_cast<QPainterWindowPixmap*>(*it);
if (pixmap->subSurface().isNull() || pixmap->subSurface()->surface().isNull() || !pixmap->subSurface()->surface()->isMapped()) {
continue;
}
paintSubSurface(painter, p, pixmap);
}
}
static bool isXwaylandClient(Toplevel *toplevel)
{
X11Client *client = qobject_cast<X11Client *>(toplevel);
if (client) {
return true;
}
Deleted *deleted = qobject_cast<Deleted *>(toplevel);
if (deleted) {
return deleted->wasX11Client();
}
return false;
}
void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const WindowPaintData &data)
{
QRegion region = _region;
......@@ -299,28 +268,7 @@ void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const
}
renderShadow(painter);
renderWindowDecorations(painter);
// render content
QRect source;
QRect target;
if (isXwaylandClient(toplevel)) {
// special case for XWayland windows
source = QRect(toplevel->clientPos(), toplevel->clientSize());
target = source;
} else {
source = pixmap->image().rect();
target = toplevel->bufferGeometry().translated(-pos());
}
painter->drawImage(target, pixmap->image(), source);
// render subsurfaces
const auto &children = pixmap->children();
for (auto pixmap : children) {
if (pixmap->subSurface().isNull() || pixmap->subSurface()->surface().isNull() || !pixmap->subSurface()->surface()->isMapped()) {
continue;
}
paintSubSurface(painter, bufferOffset(), static_cast<QPainterWindowPixmap*>(pixmap));
}
renderWindowPixmap(painter, pixmap);
if (!opaque) {
tempPainter.restore();
......@@ -336,6 +284,30 @@ void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const
painter->restore();
}
void SceneQPainter::Window::renderWindowPixmap(QPainter *painter, QPainterWindowPixmap *windowPixmap)
{
const QRegion shape = windowPixmap->shape();
for (const QRectF &rect : shape) {
const QPointF windowTopLeft = windowPixmap->mapToWindow(rect.topLeft());
const QPointF windowBottomRight = windowPixmap->mapToWindow(rect.bottomRight());
const QPointF bufferTopLeft = windowPixmap->mapToBuffer(rect.topLeft());
const QPointF bufferBottomRight = windowPixmap->mapToBuffer(rect.bottomRight());
painter->drawImage(QRectF(windowTopLeft, windowBottomRight),
windowPixmap->image(),
QRectF(bufferTopLeft, bufferBottomRight));
}
const QVector<WindowPixmap *> children = windowPixmap->children();
for (WindowPixmap *child : children) {
QPainterWindowPixmap *scenePixmap = static_cast<QPainterWindowPixmap *>(child);
if (scenePixmap->isValid()) {
renderWindowPixmap(painter, scenePixmap);
}
}
}
void SceneQPainter::Window::renderShadow(QPainter* painter)
{
if (!toplevel->shadow()) {
......
......@@ -71,20 +71,6 @@ private:
class Window;
};
class SceneQPainter::Window : public Scene::Window
{
public:
Window(SceneQPainter *scene, Toplevel *c);
~Window() override;
void performPaint(int mask, const QRegion &region, const WindowPaintData &data) override;
protected:
WindowPixmap *createWindowPixmap() override;
private:
void renderShadow(QPainter *painter);
void renderWindowDecorations(QPainter *painter);
SceneQPainter *m_scene;
};
class QPainterWindowPixmap : public WindowPixmap
{
public:
......@@ -103,6 +89,21 @@ private:
QImage m_image;
};
class SceneQPainter::Window : public Scene::Window
{
public:
Window(SceneQPainter *scene, Toplevel *c);
~Window() override;
void performPaint(int mask, const QRegion &region, const WindowPaintData &data) override;
protected:
WindowPixmap *createWindowPixmap() override;
private:
void renderWindowPixmap(QPainter *painter, QPainterWindowPixmap *windowPixmap);
void renderShadow(QPainter *painter);
void renderWindowDecorations(QPainter *painter);
SceneQPainter *m_scene;
};
class QPainterEffectFrame : public Scene::EffectFrame
{
public:
......
......@@ -1028,30 +1028,28 @@ WindowQuadList Scene::Window::makeContentsQuads() const
continue;
const QRegion region = windowPixmap->shape();
const QPoint position = windowPixmap->framePosition();
const qreal scale = windowPixmap->scale();
const int quadId = id++;
for (const QRect &rect : region) {
for (const QRectF &rect : region) {
// Note that the window quad id is not unique if the window is shaped, i.e. the
// region contains more than just one rectangle. We assume that the "source" quad
// had been subdivided.
WindowQuad quad(WindowQuadContents, quadId);
const qreal x0 = rect.x() + position.x();
const qreal y0 = rect.y() + position.y();
const qreal x1 = rect.x() + rect.width() + position.x();
const qreal y1 = rect.y() + rect.height() + position.y();
const QPointF windowTopLeft = windowPixmap->mapToWindow(rect.topLeft());
const QPointF windowTopRight = windowPixmap->mapToWindow(rect.topRight());
const QPointF windowBottomRight = windowPixmap->mapToWindow(rect.bottomRight());
const QPointF windowBottomLeft = windowPixmap->mapToWindow(rect.bottomLeft());
const qreal u0 = rect.x() * scale;
const qreal v0 = rect.y() * scale;
const qreal u1 = (rect.x() + rect.width()) * scale;
const qreal v1 = (rect.y() + rect.height()) * scale;
const QPointF bufferTopLeft = windowPixmap->mapToBuffer(rect.topLeft());
const QPointF bufferTopRight = windowPixmap->mapToBuffer(rect.topRight());
const QPointF bufferBottomRight = windowPixmap->mapToBuffer(rect.bottomRight());
const QPointF bufferBottomLeft = windowPixmap->mapToBuffer(rect.bottomLeft());
quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0));
quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0));
quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1));
quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1));
quad[0] = WindowVertex(windowTopLeft, bufferTopLeft);
quad[1] = WindowVertex(windowTopRight, bufferTopRight);
quad[2] = WindowVertex(windowBottomRight, bufferBottomRight);
quad[3] = WindowVertex(windowBottomLeft, bufferBottomLeft);
quads << quad;
}
......@@ -1288,6 +1286,16 @@ bool WindowPixmap::hasAlphaChannel() const
return toplevel()->hasAlpha();
}
QPointF WindowPixmap::mapToWindow(const QPointF &point) const
{
return point + framePosition();
}
QPointF WindowPixmap::mapToBuffer(const QPointF &point) const
{
return point * scale();
}
//****************************************
// Scene::EffectFrame
//****************************************
......
......@@ -502,6 +502,14 @@ public:
* Returns @c true if the attached buffer has an alpha channel; otherwise returns @c false.
*/
bool hasAlphaChannel() const;
/**
* Maps the specified @a point from the window pixmap coordinates to the window local coordinates.
*/
QPointF mapToWindow(const QPointF &point) const;
/**
* Maps the specified @a point from the window pixmap coordinates to the buffer pixel coordinates.
*/
QPointF mapToBuffer(const QPointF &point) const;
/**
* @returns the parent WindowPixmap in the sub-surface tree
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment