[education/rkward] rkward/rbackend/rkwarddevice: More transparent mapping of graphics enums that have a direct correspondence between R and Qt

Thomas Friedrichsmeier null at kde.org
Sat Mar 26 08:53:32 GMT 2022


Git commit 7f98f6874f5933286c3350c448c104edae5ba2cf by Thomas Friedrichsmeier.
Committed on 26/03/2022 at 08:31.
Pushed by tfry into branch 'master'.

More transparent mapping of graphics enums that have a direct correspondence between R and Qt

M  +1    -0    rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
M  +4    -4    rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
M  +29   -21   rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
M  +1    -6    rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp

https://invent.kde.org/education/rkward/commit/7f98f6874f5933286c3350c448c104edae5ba2cf

diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
index a0bf9815..c442c235 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice.cpp
@@ -273,6 +273,7 @@ void RKGraphicsDevice::destroyPattern(int id) {
 void RKGraphicsDevice::startRecordPath() {
 	RK_TRACE(GRAPHICS_DEVICE);
 
+	// Not really sure whether R uses nested clipping paths at all, but not a big deal to support them, here.
 	stashed_paths.append(recorded_path);
 	recorded_path = QPainterPath();
 	recording_path = true;
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
index 50fc0f90..b659db46 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
@@ -128,16 +128,16 @@ static QPen readPen (QDataStream &instream) {
 	quint8 lends, ljoin;
 	double lmitre;
 	instream >> lends >> ljoin >> lmitre;
-	ret.setCapStyle (lends == RoundLineCap ? Qt::RoundCap : (lends == ButtLineCap ? Qt::FlatCap : Qt::SquareCap));
-	ret.setJoinStyle (ljoin == RoundJoin ? Qt::RoundJoin : (ljoin == BevelJoin ? Qt::BevelJoin : Qt::MiterJoin));
-	ret.setMiterLimit (lmitre);
+	ret.setCapStyle((Qt::PenCapStyle) mapLineEndStyle(lends));
+	ret.setJoinStyle((Qt::PenJoinStyle) mapLineJoinStyle(ljoin));
+	ret.setMiterLimit(lmitre);
 	return ret;
 }
 
 static QBrush readBrush(QDataStream &instream, RKGraphicsDevice *dev) {
 	qint8 filltype;
 	instream >> filltype;
-	if (filltype  == ColorFill) {
+	if (filltype == ColorFill) {
 		QColor col = readColor(instream);
 		return QBrush(col);
 	} else {
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
index 80e4dc2e..645a804c 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_protocol_shared.h
@@ -44,22 +44,6 @@
  * 
  */
 
-/** This enum simply repeats R's line end definitions. It is used to ensure compatibility, without the need to include
- * any R headers in the frontend. */
-enum RKLineEndStyles {
-	RoundLineCap = 1,
-	ButtLineCap = 2,
-	SquareLineCap = 3
-};
-
-/** This enum simply repeats R's line join definitions. It is used to ensure compatibility, without the need to include
- * any R headers in the frontend. */
-enum RKLineJoinStyles {
-	RoundJoin = 1,
-	MitreJoin = 2,
-	BevelJoin = 3
-};
-
 enum RKDFillType {
 	ColorFill,
 	PatternFill
@@ -152,7 +136,7 @@ enum RKDEventCodes {
  * While in most cases there _is_ a direct correspondence, the underlying int values cannot be assumed to be the same (and in many cases differ).
  * Thus we need a lot of code along the lines "if(value = r_enum_value) return qt_enum_value;".
  *
- * As a further complication, we cannot easily include R headers in frontend code, and not easily (arbitray) Qt headers in backend code, thus the
+ * As a further complication, we cannot easily include R headers in frontend code, or (arbitray) Qt headers in backend code, thus the
  * above pseudo code will lack either the Qt or the R defintion. At some point we need to map to a value we set ourselves, either a third, rk-specific, enum,
  * or a naked int.
  *
@@ -164,15 +148,39 @@ enum RKDEventCodes {
  */
 #if defined(RKD_BACKEND_CODE)
 #define MapEnum(Rval,Ival,Qval) case Rval: return Ival;
-#define MapDefault(Ival,Qval) return Ival;
+#define MapDefault(Message,Ival,Qval) Message; return Ival;
+#define RKD_IN_FRONTEND false
 #else
 #define MapEnum(Rval,Ival,Qval) case Ival: static_assert(Ival == (int) Qval, "Enum mismatch"); return Qval;
-#define MapDefault(Ival,Qval) return Qval;
+#define MapDefault(Message,Ival,Qval) return Qval;
+#define RKD_IN_FRONTEND true
 #define RKD_RGE_VERSION 99999
 #endif
 
+static inline quint8 mapLineEndStyle(quint8 from) {
+	if (RKD_IN_FRONTEND) return from;
+	switch(from) {
+		MapEnum(GE_BUTT_CAP, 0x00, Qt::FlatCap);
+		MapEnum(GE_SQUARE_CAP, 0x10, Qt::SquareCap);
+		MapEnum(GE_ROUND_CAP, 0x20, Qt::RoundCap);
+	}
+	MapDefault({}, 0x00, Qt::FlatCap);
+}
+
+static inline quint8 mapLineJoinStyle(quint8 from) {
+	if (RKD_IN_FRONTEND) return from;
+	switch(from) {
+		MapEnum(GE_MITRE_JOIN, 0x00, Qt::MiterJoin);
+		MapEnum(GE_BEVEL_JOIN, 0x40, Qt::BevelJoin);
+		MapEnum(GE_ROUND_JOIN, 0x80, Qt::RoundJoin);
+		//MapEnum(GE_ROUND_JOIN, 0x100, Qt::SvgMiterJoin);  // not available in R, and wouldn't fit in quint8
+	}
+	MapDefault({}, 0x00, Qt::MiterJoin);
+}
+
 #if RKD_RGE_VERSION >= 15
-static int mapCompostionModeEnum(int from) {
+static inline int mapCompostionModeEnum(int from) {
+	if (RKD_IN_FRONTEND) return from;
 	switch(from) {
 		MapEnum(R_GE_compositeClear, 2, QPainter::CompositionMode_Clear);
 		MapEnum(R_GE_compositeSource, 3, QPainter::CompositionMode_Source);
@@ -201,7 +209,7 @@ static int mapCompostionModeEnum(int from) {
 // Unsupported in Qt:
 // MapEnum(R_GE_compositeSaturate, xx, yy)
 	}
-	MapDefault(0, QPainter::CompositionMode_SourceOver);
+	MapDefault(Rf_warning("Unsupported enumeration value %d", from), 0, QPainter::CompositionMode_SourceOver);
 }
 #endif
 
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
index 4dc7cdd3..90ed87b4 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
@@ -162,11 +162,6 @@ public:
 #include <QRectF>
 #include <QSizeF>
 
-// This ought to be optimized away by the compiler:
-#define SAFE_LINE_END(lend) (quint8) (lend == GE_ROUND_CAP ? RoundLineCap : (lend == GE_BUTT_CAP ? ButtLineCap : SquareLineCap))
-// This ought to be optimized away by the compiler:
-#define SAFE_LINE_JOIN(ljoin) (quint8) (ljoin == GE_ROUND_JOIN ? RoundJoin : (ljoin == GE_BEVEL_JOIN ? BevelJoin : MitreJoin))
-
 // I'd love to convert to QColor, directly, but that's in QtGui, not QtCore. QRgb used different byte ordering
 // TODO: is the check against NA_INTEGER needed at all?
 #define WRITE_COLOR_BYTES(col) \
@@ -181,7 +176,7 @@ public:
 	WRITE_COL(); RKD_OUT_STREAM << (double) gc->lwd << (qint32) gc->lty
 // actually lmitre is only needed if linejoin is GE_MITRE_JOIN, so we could optimize a bit
 #define WRITE_LINE_ENDS() \
-	RKD_OUT_STREAM << SAFE_LINE_END (gc->lend) << SAFE_LINE_JOIN (gc->ljoin) << gc->lmitre
+	RKD_OUT_STREAM << (quint8) mapLineEndStyle(gc->lend) << (quint8) mapLineJoinStyle(gc->ljoin) << gc->lmitre
 #if R_VERSION >= R_Version(4, 1, 0)
 #  define WRITE_FILL() \
 	if (gc->patternFill != R_NilValue) RKD_OUT_STREAM << (qint8) PatternFill << (qint16) (INTEGER(gc->patternFill)[0]); \



More information about the rkward-tracker mailing list