[education/rkward] /: Force Qt to actually sync paint operations before and after recording a tiling pattern.
Thomas Friedrichsmeier
null at kde.org
Sat Mar 19 21:57:45 GMT 2022
Git commit dc73742f4aec2ab57af17cc7b6aef345d876c68f by Thomas Friedrichsmeier.
Committed on 18/03/2022 at 22:37.
Pushed by tfry into branch 'master'.
Force Qt to actually sync paint operations before and after recording a tiling pattern.
M +1 -1 ChangeLog
M +16 -0 rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
M +1 -0 rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
M +4 -0 rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
M +1 -0 rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
M +16 -0 rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
https://invent.kde.org/education/rkward/commit/dc73742f4aec2ab57af17cc7b6aef345d876c68f
diff --git a/ChangeLog b/ChangeLog
index d7a93261..023df0e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,11 @@
TODO:
- RKDClose needs to be synchronous to avoid race-condition while closing device
-- Sometimes pattern takes bits from main paint area? Some syncing needed?
TODOS for autotests:
- Check and update the standards files
- Use options(warn=1), in order to get warnings into the test?
+- Implement new R graphics functions: gradients, patterns, clip paths
- Add icons to settings dialog for quick visual orientation
- Merge ktexteditor (script) settings into the main settings dialog
- Internal: Code cleanup around settings
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
index f5602df2..c0b59e1f 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
@@ -186,6 +186,22 @@ void RKGraphicsDevice::updateNow () {
beginPainter();
}
+/** This is definitely lame, but at least as of Qt 5.12.8, calling QPainter::end() does _not_ mean, changes are synced to the
+ * paint device. They will be synced, eventually, but when trying to capture a tiling pattern, we want a clean separation
+ * between the paints going to the main canvas and those going to the pattern space, immediately.
+ *
+ * This function achieves that. Note that it is also implemented as a synchronous operation on the stream, so Qt will definitely
+ * get around to process some events after this was called, which is probably also needed.
+ *
+ * Without this function artifacts will occur inside tiling patterns some, but not all of the time.
+ *
+ * KF6 TODO: check if still needed with Qt6. */
+void RKGraphicsDevice::forceSync() {
+ RK_TRACE (GRAPHICS_DEVICE);
+ updateNow();
+ if(painter.isActive()) painter.end();
+}
+
void RKGraphicsDevice::checkSize() {
RK_TRACE (GRAPHICS_DEVICE);
if (view->size () != area.size ()) {
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
index 954e3d9b..4ebbc72a 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.h
@@ -103,6 +103,7 @@ public:
int cachePath(QPainterPath &path);
void destroyCachedPath(int index);
bool setClipToCachedPath(int index);
+ void forceSync();
public slots:
void stopInteraction ();
signals:
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
index 81334090..72c0163e 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
@@ -440,6 +440,10 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
streamer.writeOutBuffer ();
} else if (opcode == RKDNewPageConfirm) {
device->confirmNewPage ();
+ } else if (opcode == RKDForceSync) {
+ device->forceSync();
+ streamer.outstream << (qint8) 0;
+ streamer.writeOutBuffer();
} else {
RK_DEBUG (GRAPHICS_DEVICE, DL_ERROR, "Unhandled operation of type %d for device number %d. Skipping.", opcode, devnum+1);
}
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
index a0310b10..afadb26f 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
@@ -123,6 +123,7 @@ enum RKDOpcodes {
RKDEndRecordTilingPattern, // part of setPattern in R
RKDSetClipPath, // 110
RKDEndRecordClipPath,
+ RKDForceSync,
// Protocol operations
RKDCancel = 200
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
index cf992fd4..f82b5d87 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
@@ -613,6 +613,20 @@ SEXP makeInt(int val) {
return ret;
}
+void forceSync(pDevDesc dev) {
+// NOTE: See commen7 in RKGraphicsDevice::forceSync();
+// KF6 TODO: Still neded with Qt6?
+ {
+ RKGraphicsDataStreamWriteGuard wguard;
+ WRITE_HEADER(RKDForceSync, dev);
+ }
+ {
+ RKGraphicsDataStreamReadGuard rguard;
+ qint8 dummy;
+ RKD_IN_STREAM >> dummy;
+ }
+}
+
SEXP RKD_SetPattern (SEXP pattern, pDevDesc dev) {
auto ptype = R_GE_patternType(pattern);
if ((ptype == R_GE_linearGradientPattern) || (ptype == R_GE_radialGradientPattern)) {
@@ -641,6 +655,7 @@ SEXP RKD_SetPattern (SEXP pattern, pDevDesc dev) {
RKD_OUT_STREAM << getGradientExtend(R_GE_radialGradientExtend(pattern));
}
} else if (ptype == R_GE_tilingPattern) {
+ forceSync(dev);
{
RKGraphicsDataStreamWriteGuard wguard;
WRITE_HEADER(RKDStartRecordTilingPattern, dev);
@@ -653,6 +668,7 @@ SEXP RKD_SetPattern (SEXP pattern, pDevDesc dev) {
SEXP pattern_func = PROTECT(Rf_lang1(R_GE_tilingPatternFunction(pattern)));
R_tryEval(pattern_func, R_GlobalEnv, &error);
UNPROTECT(1);
+ forceSync(dev);
{
RKGraphicsDataStreamWriteGuard wguard;
WRITE_HEADER(RKDEndRecordTilingPattern, dev);
More information about the rkward-tracker
mailing list