[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
2020-01-14 16:17:18 +00:00
|
|
|
Copyright (C) 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QObject>
|
|
|
|
#include <QPair>
|
|
|
|
#include <QVector>
|
|
|
|
|
|
|
|
#include <KDecoration2/Decoration>
|
|
|
|
#include <KDecoration2/DecorationShadow>
|
|
|
|
|
|
|
|
#include <KWayland/Client/server_decoration.h>
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
#include <KWayland/Client/shadow.h>
|
|
|
|
#include <KWayland/Client/shm_pool.h>
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
#include <KWayland/Client/surface.h>
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
#include <KWayland/Server/shadow_interface.h>
|
|
|
|
#include <KWayland/Server/surface_interface.h>
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
|
|
|
|
#include "kwin_wayland_test.h"
|
|
|
|
|
2020-03-04 07:55:26 +00:00
|
|
|
#include "abstract_client.h"
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
#include "composite.h"
|
|
|
|
#include "effect_builtins.h"
|
|
|
|
#include "effectloader.h"
|
|
|
|
#include "effects.h"
|
|
|
|
#include "platform.h"
|
|
|
|
#include "shadow.h"
|
|
|
|
#include "wayland_server.h"
|
|
|
|
#include "workspace.h"
|
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(KWin::WindowQuadList);
|
|
|
|
|
|
|
|
using namespace KWin;
|
|
|
|
using namespace KWayland::Client;
|
|
|
|
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_scene_opengl_shadow-0");
|
|
|
|
|
|
|
|
class SceneOpenGLShadowTest : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
SceneOpenGLShadowTest() {}
|
|
|
|
|
|
|
|
private Q_SLOTS:
|
|
|
|
void initTestCase();
|
|
|
|
void cleanup();
|
|
|
|
|
|
|
|
void testShadowTileOverlaps_data();
|
|
|
|
void testShadowTileOverlaps();
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
void testNoCornerShadowTiles();
|
|
|
|
void testDistributeHugeCornerTiles();
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool isClose(double a, double b, double eps = 1e-5)
|
|
|
|
{
|
|
|
|
if (a == b) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
const double diff = std::fabs(a - b);
|
|
|
|
if (a == 0 || b == 0) {
|
|
|
|
return diff < eps;
|
|
|
|
}
|
|
|
|
return diff / std::max(a, b) < eps;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool compareQuads(const WindowQuad &a, const WindowQuad &b)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if (!isClose(a[i].x(), b[i].x())
|
|
|
|
|| !isClose(a[i].y(), b[i].y())
|
|
|
|
|| !isClose(a[i].u(), b[i].u())
|
|
|
|
|| !isClose(a[i].v(), b[i].v())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline WindowQuad makeShadowQuad(const QRectF &geo, qreal tx1, qreal ty1, qreal tx2, qreal ty2)
|
|
|
|
{
|
|
|
|
WindowQuad quad(WindowQuadShadow);
|
|
|
|
quad[0] = WindowVertex(geo.left(), geo.top(), tx1, ty1);
|
|
|
|
quad[1] = WindowVertex(geo.right(), geo.top(), tx2, ty1);
|
|
|
|
quad[2] = WindowVertex(geo.right(), geo.bottom(), tx2, ty2);
|
|
|
|
quad[3] = WindowVertex(geo.left(), geo.bottom(), tx1, ty2);
|
|
|
|
return quad;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SceneOpenGLShadowTest::initTestCase()
|
|
|
|
{
|
|
|
|
// Copied from generic_scene_opengl_test.cpp
|
|
|
|
|
|
|
|
qRegisterMetaType<KWin::AbstractClient*>();
|
|
|
|
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
|
|
|
|
QVERIFY(workspaceCreatedSpy.isValid());
|
|
|
|
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
|
|
|
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
|
|
|
|
|
|
|
|
// disable all effects - we don't want to have it interact with the rendering
|
|
|
|
auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
|
|
|
|
KConfigGroup plugins(config, QStringLiteral("Plugins"));
|
|
|
|
ScriptedEffectLoader loader;
|
|
|
|
const auto builtinNames = BuiltInEffects::availableEffectNames() << loader.listOfKnownEffects();
|
|
|
|
for (QString name : builtinNames) {
|
|
|
|
plugins.writeEntry(name + QStringLiteral("Enabled"), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
config->sync();
|
|
|
|
kwinApp()->setConfig(config);
|
|
|
|
|
|
|
|
qputenv("XCURSOR_THEME", QByteArrayLiteral("DMZ-White"));
|
|
|
|
qputenv("XCURSOR_SIZE", QByteArrayLiteral("24"));
|
|
|
|
qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
|
|
|
|
|
|
|
|
kwinApp()->start();
|
|
|
|
QVERIFY(workspaceCreatedSpy.wait());
|
|
|
|
QVERIFY(KWin::Compositor::self());
|
|
|
|
|
|
|
|
// Add directory with fake decorations to the plugin search path.
|
|
|
|
QCoreApplication::addLibraryPath(
|
|
|
|
QDir(QCoreApplication::applicationDirPath()).absoluteFilePath("fakes")
|
|
|
|
);
|
|
|
|
|
|
|
|
// Change decoration theme.
|
|
|
|
KConfigGroup group = kwinApp()->config()->group("org.kde.kdecoration2");
|
|
|
|
group.writeEntry("library", "org.kde.test.fakedecowithshadows");
|
|
|
|
group.sync();
|
|
|
|
Workspace::self()->slotReconfigure();
|
|
|
|
|
2019-01-06 15:34:10 +00:00
|
|
|
auto scene = KWin::Compositor::self()->scene();
|
|
|
|
QVERIFY(scene);
|
|
|
|
QCOMPARE(scene->compositingType(), KWin::OpenGL2Compositing);
|
|
|
|
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SceneOpenGLShadowTest::cleanup()
|
|
|
|
{
|
|
|
|
Test::destroyWaylandConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
const int SHADOW_SIZE = 128;
|
|
|
|
|
|
|
|
const int SHADOW_OFFSET_TOP = 64;
|
|
|
|
const int SHADOW_OFFSET_LEFT = 48;
|
|
|
|
|
|
|
|
// NOTE: We assume deco shadows are generated with blur so that's
|
|
|
|
// why there is 4, 1 is the size of the inner shadow rect.
|
|
|
|
const int SHADOW_TEXTURE_WIDTH = 4 * SHADOW_SIZE + 1;
|
|
|
|
const int SHADOW_TEXTURE_HEIGHT = 4 * SHADOW_SIZE + 1;
|
|
|
|
|
|
|
|
const int SHADOW_PADDING_TOP = SHADOW_SIZE - SHADOW_OFFSET_TOP;
|
|
|
|
const int SHADOW_PADDING_RIGHT = SHADOW_SIZE + SHADOW_OFFSET_LEFT;
|
|
|
|
const int SHADOW_PADDING_BOTTOM = SHADOW_SIZE + SHADOW_OFFSET_TOP;
|
|
|
|
const int SHADOW_PADDING_LEFT = SHADOW_SIZE - SHADOW_OFFSET_LEFT;
|
|
|
|
|
|
|
|
const QRectF SHADOW_INNER_RECT(2 * SHADOW_SIZE, 2 * SHADOW_SIZE, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SceneOpenGLShadowTest::testShadowTileOverlaps_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QSize>("windowSize");
|
|
|
|
QTest::addColumn<WindowQuadList>("expectedQuads");
|
|
|
|
|
|
|
|
// Precompute shadow tile geometries(in texture's space).
|
|
|
|
const QRectF topLeftTile(
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
SHADOW_INNER_RECT.x(),
|
|
|
|
SHADOW_INNER_RECT.y());
|
|
|
|
const QRectF topRightTile(
|
|
|
|
SHADOW_INNER_RECT.right(),
|
|
|
|
0,
|
|
|
|
SHADOW_TEXTURE_WIDTH - SHADOW_INNER_RECT.right(),
|
|
|
|
SHADOW_INNER_RECT.y());
|
|
|
|
const QRectF topTile(topLeftTile.topRight(), topRightTile.bottomLeft());
|
|
|
|
|
|
|
|
const QRectF bottomLeftTile(
|
|
|
|
0,
|
|
|
|
SHADOW_INNER_RECT.bottom(),
|
|
|
|
SHADOW_INNER_RECT.x(),
|
|
|
|
SHADOW_TEXTURE_HEIGHT - SHADOW_INNER_RECT.bottom());
|
|
|
|
const QRectF bottomRightTile(
|
|
|
|
SHADOW_INNER_RECT.right(),
|
|
|
|
SHADOW_INNER_RECT.bottom(),
|
|
|
|
SHADOW_TEXTURE_WIDTH - SHADOW_INNER_RECT.right(),
|
|
|
|
SHADOW_TEXTURE_HEIGHT - SHADOW_INNER_RECT.bottom());
|
|
|
|
const QRectF bottomTile(bottomLeftTile.topRight(), bottomRightTile.bottomLeft());
|
|
|
|
|
|
|
|
const QRectF leftTile(topLeftTile.bottomLeft(), bottomLeftTile.topRight());
|
|
|
|
const QRectF rightTile(topRightTile.bottomLeft(), bottomRightTile.topRight());
|
|
|
|
|
|
|
|
qreal tx1 = 0;
|
|
|
|
qreal ty1 = 0;
|
|
|
|
qreal tx2 = 0;
|
|
|
|
qreal ty2 = 0;
|
|
|
|
|
|
|
|
// Explanation behind numbers: (256+1 x 256+1) is the minimum window size
|
|
|
|
// which doesn't cause overlapping of shadow tiles. For example, if a window
|
|
|
|
// has (256 x 256+1) size, top-left and top-right or bottom-left and
|
|
|
|
// bottom-right shadow tiles overlap.
|
|
|
|
|
|
|
|
// No overlaps: In this case corner tiles are rendered as they are,
|
|
|
|
// and top/right/bottom/left tiles are stretched.
|
|
|
|
{
|
|
|
|
const QSize windowSize(256 + 1, 256 + 1);
|
|
|
|
WindowQuadList shadowQuads;
|
|
|
|
|
|
|
|
const QRectF outerRect(
|
|
|
|
-SHADOW_PADDING_LEFT,
|
|
|
|
-SHADOW_PADDING_TOP,
|
|
|
|
windowSize.width() + SHADOW_PADDING_LEFT + SHADOW_PADDING_RIGHT,
|
|
|
|
windowSize.height() + SHADOW_PADDING_TOP + SHADOW_PADDING_BOTTOM);
|
|
|
|
|
|
|
|
const QRectF topLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.top(),
|
|
|
|
topLeftTile.width(),
|
|
|
|
topLeftTile.height());
|
|
|
|
tx1 = topLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topLeftTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF topRight(
|
|
|
|
outerRect.right() - topRightTile.width(),
|
|
|
|
outerRect.top(),
|
|
|
|
topRightTile.width(),
|
|
|
|
topRightTile.height());
|
|
|
|
tx1 = topRightTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF top(topLeft.topRight(), topRight.bottomLeft());
|
|
|
|
tx1 = topTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(top, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF bottomLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.bottom() - bottomLeftTile.height(),
|
|
|
|
bottomLeftTile.width(),
|
|
|
|
bottomLeftTile.height());
|
|
|
|
tx1 = bottomLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = bottomLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = bottomLeftTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF bottomRight(
|
|
|
|
outerRect.right() - bottomRightTile.width(),
|
|
|
|
outerRect.bottom() - bottomRightTile.height(),
|
|
|
|
bottomRightTile.width(),
|
|
|
|
bottomRightTile.height());
|
|
|
|
tx1 = bottomRightTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = bottomRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = bottomRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF bottom(bottomLeft.topRight(), bottomRight.bottomLeft());
|
|
|
|
tx1 = bottomTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = bottomTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = bottomTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottom, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF left(topLeft.bottomLeft(), bottomLeft.topRight());
|
|
|
|
tx1 = leftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = leftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = leftTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = leftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(left, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF right(topRight.bottomLeft(), bottomRight.topRight());
|
|
|
|
tx1 = rightTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = rightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = rightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = rightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(right, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QTest::newRow("no overlaps") << windowSize << shadowQuads;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Top-Left & Bottom-Left/Top-Right & Bottom-Right overlap:
|
|
|
|
// In this case overlapping parts are clipped and left/right
|
|
|
|
// tiles aren't rendered.
|
|
|
|
const QVector<QPair<QByteArray, QSize>> verticalOverlapTestTable {
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("top-left & bottom-left/top-right & bottom-right overlap"),
|
|
|
|
QSize(256 + 1, 256)
|
|
|
|
},
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("top-left & bottom-left/top-right & bottom-right overlap :: pre"),
|
|
|
|
QSize(256 + 1, 256 - 1)
|
|
|
|
}
|
|
|
|
// No need to test the case when window size is QSize(256 + 1, 256 + 1).
|
|
|
|
// It has been tested already (no overlaps test case).
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto const &tt : verticalOverlapTestTable) {
|
|
|
|
const char *testName = tt.first.constData();
|
|
|
|
const QSize windowSize = tt.second;
|
|
|
|
|
|
|
|
WindowQuadList shadowQuads;
|
|
|
|
qreal halfOverlap = 0.0;
|
|
|
|
|
|
|
|
const QRectF outerRect(
|
|
|
|
-SHADOW_PADDING_LEFT,
|
|
|
|
-SHADOW_PADDING_TOP,
|
|
|
|
windowSize.width() + SHADOW_PADDING_LEFT + SHADOW_PADDING_RIGHT,
|
|
|
|
windowSize.height() + SHADOW_PADDING_TOP + SHADOW_PADDING_BOTTOM);
|
|
|
|
|
|
|
|
QRectF topLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.top(),
|
|
|
|
topLeftTile.width(),
|
|
|
|
topLeftTile.height());
|
|
|
|
|
|
|
|
QRectF bottomLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.bottom() - bottomLeftTile.height(),
|
|
|
|
bottomLeftTile.width(),
|
|
|
|
bottomLeftTile.height());
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topLeft.bottom() - bottomLeft.top()) / 2;
|
|
|
|
topLeft.setBottom(topLeft.bottom() - halfOverlap);
|
|
|
|
bottomLeft.setTop(bottomLeft.top() + halfOverlap);
|
|
|
|
|
|
|
|
tx1 = topLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topLeftTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topLeft.height() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = bottomLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = 1.0 - (bottomLeft.height() / SHADOW_TEXTURE_HEIGHT);
|
|
|
|
tx2 = bottomLeftTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QRectF topRight(
|
|
|
|
outerRect.right() - topRightTile.width(),
|
|
|
|
outerRect.top(),
|
|
|
|
topRightTile.width(),
|
|
|
|
topRightTile.height());
|
|
|
|
|
|
|
|
QRectF bottomRight(
|
|
|
|
outerRect.right() - bottomRightTile.width(),
|
|
|
|
outerRect.bottom() - bottomRightTile.height(),
|
|
|
|
bottomRightTile.width(),
|
|
|
|
bottomRightTile.height());
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topRight.bottom() - bottomRight.top()) / 2;
|
|
|
|
topRight.setBottom(topRight.bottom() - halfOverlap);
|
|
|
|
bottomRight.setTop(bottomRight.top() + halfOverlap);
|
|
|
|
|
|
|
|
tx1 = topRightTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topRight.height() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = bottomRightTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = 1.0 - (bottomRight.height() / SHADOW_TEXTURE_HEIGHT);
|
|
|
|
tx2 = bottomRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF top(topLeft.topRight(), topRight.bottomLeft());
|
|
|
|
tx1 = topTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = top.height() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(top, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF bottom(bottomLeft.topRight(), bottomRight.bottomLeft());
|
|
|
|
tx1 = bottomTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = 1.0 - (bottom.height() / SHADOW_TEXTURE_HEIGHT);
|
|
|
|
tx2 = bottomTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottom, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QTest::newRow(testName) << windowSize << shadowQuads;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Top-Left & Top-Right/Bottom-Left & Bottom-Right overlap:
|
|
|
|
// In this case overlapping parts are clipped and top/bottom
|
|
|
|
// tiles aren't rendered.
|
|
|
|
const QVector<QPair<QByteArray, QSize>> horizontalOverlapTestTable {
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("top-left & top-right/bottom-left & bottom-right overlap"),
|
|
|
|
QSize(256, 256 + 1)
|
|
|
|
},
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("top-left & top-right/bottom-left & bottom-right overlap :: pre"),
|
|
|
|
QSize(256 - 1, 256 + 1)
|
|
|
|
}
|
|
|
|
// No need to test the case when window size is QSize(256 + 1, 256 + 1).
|
|
|
|
// It has been tested already (no overlaps test case).
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto const &tt : horizontalOverlapTestTable) {
|
|
|
|
const char *testName = tt.first.constData();
|
|
|
|
const QSize windowSize = tt.second;
|
|
|
|
|
|
|
|
WindowQuadList shadowQuads;
|
|
|
|
qreal halfOverlap = 0.0;
|
|
|
|
|
|
|
|
const QRectF outerRect(
|
|
|
|
-SHADOW_PADDING_LEFT,
|
|
|
|
-SHADOW_PADDING_TOP,
|
|
|
|
windowSize.width() + SHADOW_PADDING_LEFT + SHADOW_PADDING_RIGHT,
|
|
|
|
windowSize.height() + SHADOW_PADDING_TOP + SHADOW_PADDING_BOTTOM);
|
|
|
|
|
|
|
|
QRectF topLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.top(),
|
|
|
|
topLeftTile.width(),
|
|
|
|
topLeftTile.height());
|
|
|
|
|
|
|
|
QRectF topRight(
|
|
|
|
outerRect.right() - topRightTile.width(),
|
|
|
|
outerRect.top(),
|
|
|
|
topRightTile.width(),
|
|
|
|
topRightTile.height());
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topLeft.right() - topRight.left()) / 2;
|
|
|
|
topLeft.setRight(topLeft.right() - halfOverlap);
|
|
|
|
topRight.setLeft(topRight.left() + halfOverlap);
|
|
|
|
|
|
|
|
tx1 = topLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topLeft.width() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = 1.0 - (topRight.width() / SHADOW_TEXTURE_WIDTH);
|
|
|
|
ty1 = topRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QRectF bottomLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.bottom() - bottomLeftTile.height(),
|
|
|
|
bottomLeftTile.width(),
|
|
|
|
bottomLeftTile.height());
|
|
|
|
|
|
|
|
QRectF bottomRight(
|
|
|
|
outerRect.right() - bottomRightTile.width(),
|
|
|
|
outerRect.bottom() - bottomRightTile.height(),
|
|
|
|
bottomRightTile.width(),
|
|
|
|
bottomRightTile.height());
|
|
|
|
|
|
|
|
halfOverlap = qAbs(bottomLeft.right() - bottomRight.left()) / 2;
|
|
|
|
bottomLeft.setRight(bottomLeft.right() - halfOverlap);
|
|
|
|
bottomRight.setLeft(bottomRight.left() + halfOverlap);
|
|
|
|
|
|
|
|
tx1 = bottomLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = bottomLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = bottomLeft.width() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = 1.0 - (bottomRight.width() / SHADOW_TEXTURE_WIDTH);
|
|
|
|
ty1 = bottomRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = bottomRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF left(topLeft.bottomLeft(), bottomLeft.topRight());
|
|
|
|
tx1 = leftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = leftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = left.width() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = leftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(left, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
const QRectF right(topRight.bottomLeft(), bottomRight.topRight());
|
|
|
|
tx1 = 1.0 - (right.width() / SHADOW_TEXTURE_WIDTH);
|
|
|
|
ty1 = rightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = rightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = rightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(right, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QTest::newRow(testName) << windowSize << shadowQuads;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All shadow tiles overlap: In this case all overlapping parts
|
|
|
|
// are clippend and top/right/bottom/left tiles aren't rendered.
|
|
|
|
const QVector<QPair<QByteArray, QSize>> allOverlapTestTable {
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("all corner tiles overlap"),
|
|
|
|
QSize(256, 256)
|
|
|
|
},
|
|
|
|
QPair<QByteArray, QSize> {
|
|
|
|
QByteArray("all corner tiles overlap :: pre"),
|
|
|
|
QSize(256 - 1, 256 - 1)
|
|
|
|
}
|
|
|
|
// No need to test the case when window size is QSize(256 + 1, 256 + 1).
|
|
|
|
// It has been tested already (no overlaps test case).
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto const &tt : allOverlapTestTable) {
|
|
|
|
const char *testName = tt.first.constData();
|
|
|
|
const QSize windowSize = tt.second;
|
|
|
|
|
|
|
|
WindowQuadList shadowQuads;
|
|
|
|
qreal halfOverlap = 0.0;
|
|
|
|
|
|
|
|
const QRectF outerRect(
|
|
|
|
-SHADOW_PADDING_LEFT,
|
|
|
|
-SHADOW_PADDING_TOP,
|
|
|
|
windowSize.width() + SHADOW_PADDING_LEFT + SHADOW_PADDING_RIGHT,
|
|
|
|
windowSize.height() + SHADOW_PADDING_TOP + SHADOW_PADDING_BOTTOM);
|
|
|
|
|
|
|
|
QRectF topLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.top(),
|
|
|
|
topLeftTile.width(),
|
|
|
|
topLeftTile.height());
|
|
|
|
|
|
|
|
QRectF topRight(
|
|
|
|
outerRect.right() - topRightTile.width(),
|
|
|
|
outerRect.top(),
|
|
|
|
topRightTile.width(),
|
|
|
|
topRightTile.height());
|
|
|
|
|
|
|
|
QRectF bottomLeft(
|
|
|
|
outerRect.left(),
|
|
|
|
outerRect.bottom() - bottomLeftTile.height(),
|
|
|
|
bottomLeftTile.width(),
|
|
|
|
bottomLeftTile.height());
|
|
|
|
|
|
|
|
QRectF bottomRight(
|
|
|
|
outerRect.right() - bottomRightTile.width(),
|
|
|
|
outerRect.bottom() - bottomRightTile.height(),
|
|
|
|
bottomRightTile.width(),
|
|
|
|
bottomRightTile.height());
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topLeft.right() - topRight.left()) / 2;
|
|
|
|
topLeft.setRight(topLeft.right() - halfOverlap);
|
|
|
|
topRight.setLeft(topRight.left() + halfOverlap);
|
|
|
|
|
|
|
|
halfOverlap = qAbs(bottomLeft.right() - bottomRight.left()) / 2;
|
|
|
|
bottomLeft.setRight(bottomLeft.right() - halfOverlap);
|
|
|
|
bottomRight.setLeft(bottomRight.left() + halfOverlap);
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topLeft.bottom() - bottomLeft.top()) / 2;
|
|
|
|
topLeft.setBottom(topLeft.bottom() - halfOverlap);
|
|
|
|
bottomLeft.setTop(bottomLeft.top() + halfOverlap);
|
|
|
|
|
|
|
|
halfOverlap = qAbs(topRight.bottom() - bottomRight.top()) / 2;
|
|
|
|
topRight.setBottom(topRight.bottom() - halfOverlap);
|
|
|
|
bottomRight.setTop(bottomRight.top() + halfOverlap);
|
|
|
|
|
|
|
|
tx1 = topLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = topLeftTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topLeft.width() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topLeft.height() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = 1.0 - (topRight.width() / SHADOW_TEXTURE_WIDTH);
|
|
|
|
ty1 = topRightTile.top() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
tx2 = topRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = topRight.height() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(topRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = bottomLeftTile.left() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty1 = 1.0 - (bottomLeft.height() / SHADOW_TEXTURE_HEIGHT);
|
|
|
|
tx2 = bottomLeft.width() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomLeftTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomLeft, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
tx1 = 1.0 - (bottomRight.width() / SHADOW_TEXTURE_WIDTH);
|
|
|
|
ty1 = 1.0 - (bottomRight.height() / SHADOW_TEXTURE_HEIGHT);
|
|
|
|
tx2 = bottomRightTile.right() / SHADOW_TEXTURE_WIDTH;
|
|
|
|
ty2 = bottomRightTile.bottom() / SHADOW_TEXTURE_HEIGHT;
|
|
|
|
shadowQuads << makeShadowQuad(bottomRight, tx1, ty1, tx2, ty2);
|
|
|
|
|
|
|
|
QTest::newRow(testName) << windowSize << shadowQuads;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Window is too small: do not render any shadow tiles.
|
|
|
|
{
|
|
|
|
const QSize windowSize(1, 1);
|
|
|
|
const WindowQuadList shadowQuads;
|
|
|
|
|
|
|
|
QTest::newRow("window is too small") << windowSize << shadowQuads;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SceneOpenGLShadowTest::testShadowTileOverlaps()
|
|
|
|
{
|
|
|
|
QFETCH(QSize, windowSize);
|
|
|
|
QFETCH(WindowQuadList, expectedQuads);
|
|
|
|
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration));
|
|
|
|
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
// Create a decorated client.
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
2019-08-27 15:01:14 +00:00
|
|
|
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
QScopedPointer<ServerSideDecoration> ssd(Test::waylandServerSideDecoration()->create(surface.data()));
|
|
|
|
|
|
|
|
auto *client = Test::renderAndWaitForShown(surface.data(), windowSize, Qt::blue);
|
|
|
|
|
2019-08-27 15:01:14 +00:00
|
|
|
QSignalSpy sizeChangedSpy(shellSurface.data(), &XdgShellSurface::sizeChanged);
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
QVERIFY(sizeChangedSpy.isValid());
|
|
|
|
|
|
|
|
// Check the client is decorated.
|
|
|
|
QVERIFY(client);
|
|
|
|
QVERIFY(client->isDecorated());
|
|
|
|
auto *decoration = client->decoration();
|
|
|
|
QVERIFY(decoration);
|
|
|
|
|
|
|
|
// If speciefied decoration theme is not found, KWin loads a default one
|
|
|
|
// so we have to check whether a client has right decoration.
|
|
|
|
auto decoShadow = decoration->shadow();
|
|
|
|
QCOMPARE(decoShadow->shadow().size(), QSize(SHADOW_TEXTURE_WIDTH, SHADOW_TEXTURE_HEIGHT));
|
|
|
|
QCOMPARE(decoShadow->paddingTop(), SHADOW_PADDING_TOP);
|
|
|
|
QCOMPARE(decoShadow->paddingRight(), SHADOW_PADDING_RIGHT);
|
|
|
|
QCOMPARE(decoShadow->paddingBottom(), SHADOW_PADDING_BOTTOM);
|
|
|
|
QCOMPARE(decoShadow->paddingLeft(), SHADOW_PADDING_LEFT);
|
|
|
|
|
|
|
|
// Get shadow.
|
|
|
|
QVERIFY(client->effectWindow());
|
|
|
|
QVERIFY(client->effectWindow()->sceneWindow());
|
|
|
|
QVERIFY(client->effectWindow()->sceneWindow()->shadow());
|
|
|
|
auto *shadow = client->effectWindow()->sceneWindow()->shadow();
|
|
|
|
|
|
|
|
// Validate shadow quads.
|
|
|
|
const WindowQuadList &quads = shadow->shadowQuads();
|
|
|
|
QCOMPARE(quads.size(), expectedQuads.size());
|
|
|
|
|
|
|
|
QVector<bool> mask(expectedQuads.size(), false);
|
|
|
|
for (const auto &q : quads) {
|
|
|
|
for (int i = 0; i < expectedQuads.size(); i++) {
|
|
|
|
if (!compareQuads(q, expectedQuads[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!mask[i]) {
|
|
|
|
mask[i] = true;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
QFAIL("got a duplicate shadow quad");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &v : qAsConst(mask)) {
|
|
|
|
if (!v) {
|
|
|
|
QFAIL("missed a shadow quad");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
void SceneOpenGLShadowTest::testNoCornerShadowTiles()
|
|
|
|
{
|
|
|
|
// this test verifies that top/right/bottom/left shadow tiles are
|
|
|
|
// still drawn even when corner tiles are missing
|
|
|
|
|
|
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::ShadowManager));
|
|
|
|
|
|
|
|
// Create a surface.
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
2019-08-27 15:01:14 +00:00
|
|
|
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
auto *client = Test::renderAndWaitForShown(surface.data(), QSize(512, 512), Qt::blue);
|
|
|
|
QVERIFY(client);
|
|
|
|
QVERIFY(!client->isDecorated());
|
|
|
|
|
|
|
|
// Render reference shadow texture with the following params:
|
|
|
|
// - shadow size: 128
|
|
|
|
// - inner rect size: 1
|
|
|
|
// - padding: 128
|
|
|
|
QImage referenceShadowTexture(256 + 1, 256 + 1, QImage::Format_ARGB32_Premultiplied);
|
|
|
|
referenceShadowTexture.fill(Qt::transparent);
|
|
|
|
|
|
|
|
// We don't care about content of the shadow.
|
|
|
|
|
|
|
|
// Submit the shadow to KWin.
|
|
|
|
QScopedPointer<KWayland::Client::Shadow> clientShadow(Test::waylandShadowManager()->createShadow(surface.data()));
|
|
|
|
QVERIFY(clientShadow->isValid());
|
|
|
|
|
|
|
|
auto *shmPool = Test::waylandShmPool();
|
|
|
|
|
|
|
|
Buffer::Ptr bufferTop = shmPool->createBuffer(
|
|
|
|
referenceShadowTexture.copy(QRect(128, 0, 1, 128)));
|
|
|
|
clientShadow->attachTop(bufferTop);
|
|
|
|
|
|
|
|
Buffer::Ptr bufferRight = shmPool->createBuffer(
|
|
|
|
referenceShadowTexture.copy(QRect(128 + 1, 128, 128, 1)));
|
|
|
|
clientShadow->attachRight(bufferRight);
|
|
|
|
|
|
|
|
Buffer::Ptr bufferBottom = shmPool->createBuffer(
|
|
|
|
referenceShadowTexture.copy(QRect(128, 128 + 1, 1, 128)));
|
|
|
|
clientShadow->attachBottom(bufferBottom);
|
|
|
|
|
|
|
|
Buffer::Ptr bufferLeft = shmPool->createBuffer(
|
|
|
|
referenceShadowTexture.copy(QRect(0, 128, 128, 1)));
|
|
|
|
clientShadow->attachLeft(bufferLeft);
|
|
|
|
|
|
|
|
clientShadow->setOffsets(QMarginsF(128, 128, 128, 128));
|
|
|
|
|
|
|
|
QSignalSpy shadowChangedSpy(client->surface(), &KWayland::Server::SurfaceInterface::shadowChanged);
|
|
|
|
QVERIFY(shadowChangedSpy.isValid());
|
|
|
|
clientShadow->commit();
|
|
|
|
surface->commit(Surface::CommitFlag::None);
|
|
|
|
QVERIFY(shadowChangedSpy.wait());
|
|
|
|
|
|
|
|
// Check that we got right shadow from the client.
|
|
|
|
QPointer<KWayland::Server::ShadowInterface> shadowIface = client->surface()->shadow();
|
|
|
|
QVERIFY(!shadowIface.isNull());
|
|
|
|
QCOMPARE(shadowIface->offset().left(), 128.0);
|
|
|
|
QCOMPARE(shadowIface->offset().top(), 128.0);
|
|
|
|
QCOMPARE(shadowIface->offset().right(), 128.0);
|
|
|
|
QCOMPARE(shadowIface->offset().bottom(), 128.0);
|
|
|
|
|
|
|
|
QVERIFY(client->effectWindow());
|
|
|
|
QVERIFY(client->effectWindow()->sceneWindow());
|
|
|
|
KWin::Shadow *shadow = client->effectWindow()->sceneWindow()->shadow();
|
|
|
|
QVERIFY(shadow != nullptr);
|
|
|
|
|
|
|
|
const WindowQuadList &quads = shadow->shadowQuads();
|
|
|
|
QCOMPARE(quads.count(), 4);
|
|
|
|
|
|
|
|
// Shadow size: 128
|
|
|
|
// Padding: QMargins(128, 128, 128, 128)
|
|
|
|
// Inner rect: QRect(128, 128, 1, 1)
|
|
|
|
// Texture size: QSize(257, 257)
|
|
|
|
// Window size: QSize(512, 512)
|
|
|
|
WindowQuadList expectedQuads;
|
[scenes/opengl] Fix overlaps in shadow texture atlas
Summary:
If the corner shadow tiles(top-left, top-right, and so on) tiles are missing,
then the left/top/right/bottom shadow tiles will overlap.
This diff addresses that problem by changing how the shadow texture
atlas is rendered:
* corner tiles will be drawn in the corners of the atlas(buildQuads
method expects them to be at the corners);
* top, right, bottom, and left tile will be aligned to the top-left
corner of the inner shadow rect.
For majority of desktop themes, the shadow texture atlas looks the same.
For example, here's for Aether:
Before:
{F6190484, layout=center, size=full}
After:
{F6190488, layout=center, size=full}
Depends on D14783
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14784
2018-08-12 23:52:12 +00:00
|
|
|
expectedQuads << makeShadowQuad(QRectF( 0, -128, 512, 128), 128.0 / 257.0, 0.0, 129.0 / 257.0, 128.0 / 257.0); // top
|
|
|
|
expectedQuads << makeShadowQuad(QRectF( 512, 0, 128, 512), 129.0 / 257.0, 128.0 / 257.0, 1.0, 129.0 / 257.0); // right
|
|
|
|
expectedQuads << makeShadowQuad(QRectF( 0, 512, 512, 128), 128.0 / 257.0, 129.0 / 257.0, 129.0 / 257.0, 1.0); // bottom
|
|
|
|
expectedQuads << makeShadowQuad(QRectF(-128, 0, 128, 512), 0.0, 128.0 / 257.0, 128.0 / 257.0, 129.0 / 257.0); // left
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
|
|
|
|
for (const WindowQuad &expectedQuad : expectedQuads) {
|
|
|
|
auto it = std::find_if(quads.constBegin(), quads.constEnd(),
|
|
|
|
[&expectedQuad](const WindowQuad &quad) {
|
|
|
|
return compareQuads(quad, expectedQuad);
|
|
|
|
});
|
|
|
|
if (it == quads.constEnd()) {
|
|
|
|
const QString message = QStringLiteral("Missing shadow quad (left: %1, top: %2, right: %3, bottom: %4)")
|
|
|
|
.arg(expectedQuad.left())
|
|
|
|
.arg(expectedQuad.top())
|
|
|
|
.arg(expectedQuad.right())
|
|
|
|
.arg(expectedQuad.bottom());
|
|
|
|
const QByteArray rawMessage = message.toLocal8Bit().data();
|
|
|
|
QFAIL(rawMessage.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SceneOpenGLShadowTest::testDistributeHugeCornerTiles()
|
|
|
|
{
|
|
|
|
// this test verifies that huge corner tiles are distributed correctly
|
|
|
|
|
|
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::ShadowManager));
|
|
|
|
|
|
|
|
// Create a surface.
|
|
|
|
QScopedPointer<Surface> surface(Test::createSurface());
|
2019-08-27 15:01:14 +00:00
|
|
|
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
|
[scenes/opengl] Correctly draw shadows when corner tiles are missing
Summary:
Current implementation of buildQuads assumes that corner shadow tiles
are always present:
const QRectF leftRect(
topLeftRect.bottomLeft(),
bottomLeftRect.topRight());
but that assumption is wrong. For example, if the default panel is on
the bottom screen edge, then the calendar popup won't have the
bottom-left shadow tile(at least on Wayland). Which means that the left
shadow tile won't be visible because
topLeftRect.left() == bottomLeftRect.right().
Corner rectangles only have to influence height of the left/right tile
and width of the top/bottom tile. Width of the left/right tile and
height of the top/bottom tile should not be controlled by corner tiles.
Overall, this is how shadow quads are computed:
* Compute the outer rectangle;
* Compute target rectangle for each corner tile. If some corner tile is
missing, move the target rectangle to the corresponding corner of the
inner shadow rect and set its width and height to 0. We need to do
that to prevent top/right/bottom/left tiles from spanning over
corners:
{F6190219, layout=center, size=full}
We would rather prefer something like this if the top-left tile is
missing:
{F6190233, layout=center, size=full}
* Fix overlaps between corner tiles;
* Compute target rectangles for top, right, bottom, and left tiles;
* Fix overlaps between left/right and top/bottom shadow tiles.
Test Plan:
* Ran tests;
* Resized Konsole to its minimimum size(on X11 and Wayland);
* Opened the calendar popup(on X11 and Wayland):
Before:
{F6190344, layout=center, size=full}
After:
{F6190346, layout=center, size=full}
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: abetts, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14783
2018-08-12 18:23:12 +00:00
|
|
|
auto *client = Test::renderAndWaitForShown(surface.data(), QSize(64, 64), Qt::blue);
|
|
|
|
QVERIFY(client);
|
|
|
|
QVERIFY(!client->isDecorated());
|
|
|
|
|
|
|
|
// Submit the shadow to KWin.
|
|
|
|
QScopedPointer<KWayland::Client::Shadow> clientShadow(Test::waylandShadowManager()->createShadow(surface.data()));
|
|
|
|
QVERIFY(clientShadow->isValid());
|
|
|
|
|
|
|
|
QImage referenceTileTexture(512, 512, QImage::Format_ARGB32_Premultiplied);
|
|
|
|
referenceTileTexture.fill(Qt::transparent);
|
|
|
|
|
|
|
|
auto *shmPool = Test::waylandShmPool();
|
|
|
|
|
|
|
|
Buffer::Ptr bufferTopLeft = shmPool->createBuffer(referenceTileTexture);
|
|
|
|
clientShadow->attachTopLeft(bufferTopLeft);
|
|
|
|
|
|
|
|
Buffer::Ptr bufferTopRight = shmPool->createBuffer(referenceTileTexture);
|
|
|
|
clientShadow->attachTopRight(bufferTopRight);
|
|
|
|
|
|
|
|
clientShadow->setOffsets(QMarginsF(256, 256, 256, 0));
|
|
|
|
|
|
|
|
QSignalSpy shadowChangedSpy(client->surface(), &KWayland::Server::SurfaceInterface::shadowChanged);
|
|
|
|
QVERIFY(shadowChangedSpy.isValid());
|
|
|
|
clientShadow->commit();
|
|
|
|
surface->commit(Surface::CommitFlag::None);
|
|
|
|
QVERIFY(shadowChangedSpy.wait());
|
|
|
|
|
|
|
|
// Check that we got right shadow from the client.
|
|
|
|
QPointer<KWayland::Server::ShadowInterface> shadowIface = client->surface()->shadow();
|
|
|
|
QVERIFY(!shadowIface.isNull());
|
|
|
|
QCOMPARE(shadowIface->offset().left(), 256.0);
|
|
|
|
QCOMPARE(shadowIface->offset().top(), 256.0);
|
|
|
|
QCOMPARE(shadowIface->offset().right(), 256.0);
|
|
|
|
QCOMPARE(shadowIface->offset().bottom(), 0.0);
|
|
|
|
|
|
|
|
QVERIFY(client->effectWindow());
|
|
|
|
QVERIFY(client->effectWindow()->sceneWindow());
|
|
|
|
KWin::Shadow *shadow = client->effectWindow()->sceneWindow()->shadow();
|
|
|
|
QVERIFY(shadow != nullptr);
|
|
|
|
|
|
|
|
WindowQuadList expectedQuads;
|
|
|
|
|
|
|
|
// Top-left quad
|
|
|
|
expectedQuads << makeShadowQuad(
|
|
|
|
QRectF(-256, -256, 256 + 32, 256 + 64),
|
|
|
|
0.0, 0.0, (256.0 + 32.0) / 1024.0, (256.0 + 64.0) / 512.0);
|
|
|
|
|
|
|
|
// Top-right quad
|
|
|
|
expectedQuads << makeShadowQuad(
|
|
|
|
QRectF(32, -256, 256 + 32, 256 + 64),
|
|
|
|
1.0 - (256.0 + 32.0) / 1024.0, 0.0, 1.0, (256.0 + 64.0) / 512.0);
|
|
|
|
|
|
|
|
const WindowQuadList &quads = shadow->shadowQuads();
|
|
|
|
QCOMPARE(quads.count(), expectedQuads.count());
|
|
|
|
|
|
|
|
for (const WindowQuad &expectedQuad : expectedQuads) {
|
|
|
|
auto it = std::find_if(quads.constBegin(), quads.constEnd(),
|
|
|
|
[&expectedQuad](const WindowQuad &quad) {
|
|
|
|
return compareQuads(quad, expectedQuad);
|
|
|
|
});
|
|
|
|
if (it == quads.constEnd()) {
|
|
|
|
const QString message = QStringLiteral("Missing shadow quad (left: %1, top: %2, right: %3, bottom: %4)")
|
|
|
|
.arg(expectedQuad.left())
|
|
|
|
.arg(expectedQuad.top())
|
|
|
|
.arg(expectedQuad.right())
|
|
|
|
.arg(expectedQuad.bottom());
|
|
|
|
const QByteArray rawMessage = message.toLocal8Bit().data();
|
|
|
|
QFAIL(rawMessage.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[scenes/opengl] Fix overlapping shadow tiles
Summary:
This problem appears if shadow corner tiles are too big and
some window has size smaller than 2 * shadowTileSize.
This change tries to address the problem above by exclusing
overlapping tile parts. If there are any two overlapping corners
then tile between them(top/right/bottom/left) is not rendered.
Also, because some corner tile parts can be excluded, corner tiles
are expected to be symmetrical(i.e. if we remove right half from
the top-left tile and left half from the top-right tile and
stick them together, they still look fine, there are no misalignments, etc).
Most shadows(e.g. shadows from Breeze) have such behaviour.
No tiles are overlapping
{F5728514, layout=center, size=full}
Overlapping tiles
{F5728516, layout=center, size=full}
And this is how it supposed to be
{F5728517, layout=center, size=full}
Test Plan:
* apply D11069 to Breeze
* in System Settings/Application Style/Window Decorations, choose "Very Large" shadow size
* open Konsole
* resize it to a minimum possible size
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, ngraham, anemeth, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D10811
2018-06-07 08:48:05 +00:00
|
|
|
WAYLANDTEST_MAIN(SceneOpenGLShadowTest)
|
|
|
|
#include "scene_opengl_shadow_test.moc"
|