[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.
This commit is contained in:
Vlad Zahorodnii 2020-05-23 18:07:54 +03:00
parent fe83cbf034
commit 9e797cf943
4 changed files with 72 additions and 83 deletions

View file

@ -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()) {

View file

@ -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:

View file

@ -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
//****************************************

View file

@ -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