summaryrefslogtreecommitdiff
path: root/chromium/ui/gfx/x/xproto_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/gfx/x/xproto_internal.h')
-rw-r--r--chromium/ui/gfx/x/xproto_internal.h104
1 files changed, 82 insertions, 22 deletions
diff --git a/chromium/ui/gfx/x/xproto_internal.h b/chromium/ui/gfx/x/xproto_internal.h
index f76ebe5ecac..32c68b4f801 100644
--- a/chromium/ui/gfx/x/xproto_internal.h
+++ b/chromium/ui/gfx/x/xproto_internal.h
@@ -20,7 +20,9 @@
#include <type_traits>
#include "base/component_export.h"
+#include "base/logging.h"
#include "base/optional.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
@@ -49,11 +51,17 @@ struct ReadBuffer {
};
template <typename T>
-void Write(const T* t, WriteBuffer* buf) {
- static_assert(std::is_trivially_copyable<T>::value, "");
+void VerifyAlignment(T* t, size_t offset) {
// On the wire, X11 types are always aligned to their size. This is a sanity
// check to ensure padding etc are working properly.
- DCHECK_EQ(buf->size() % sizeof(*t), 0UL);
+ if (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8)
+ DCHECK_EQ(offset % sizeof(*t), 0UL);
+}
+
+template <typename T>
+void Write(const T* t, WriteBuffer* buf) {
+ static_assert(std::is_trivially_copyable<T>::value, "");
+ VerifyAlignment(t, buf->size());
const uint8_t* start = reinterpret_cast<const uint8_t*>(t);
std::copy(start, start + sizeof(*t), std::back_inserter(*buf));
}
@@ -61,9 +69,7 @@ void Write(const T* t, WriteBuffer* buf) {
template <typename T>
void Read(T* t, ReadBuffer* buf) {
static_assert(std::is_trivially_copyable<T>::value, "");
- // On the wire, X11 types are always aligned to their size. This is a sanity
- // check to ensure padding etc are working properly.
- DCHECK_EQ(buf->offset % sizeof(*t), 0UL);
+ VerifyAlignment(t, buf->offset);
memcpy(t, buf->data + buf->offset, sizeof(*t));
buf->offset += sizeof(*t);
}
@@ -85,12 +91,11 @@ inline void Align(ReadBuffer* buf, size_t align) {
}
template <typename Reply>
-Future<Reply> SendRequest(XDisplay* display, WriteBuffer* buf) {
+Future<Reply> SendRequest(x11::Connection* connection, WriteBuffer* buf) {
// Clang crashes when the value of |is_void| is inlined below,
// so keep this variable outside of |xpr|.
constexpr bool is_void = std::is_void<Reply>::value;
xcb_protocol_request_t xpr{
- .count = 1,
.ext = nullptr,
.isvoid = is_void,
};
@@ -101,23 +106,46 @@ Future<Reply> SendRequest(XDisplay* display, WriteBuffer* buf) {
uint16_t length;
};
- auto* header = reinterpret_cast<RequestHeader*>(buf->data());
+ struct ExtendedRequestHeader {
+ RequestHeader header;
+ uint32_t long_length;
+ };
+ static_assert(sizeof(ExtendedRequestHeader) == 8, "");
+
+ auto* old_header = reinterpret_cast<RequestHeader*>(buf->data());
+ ExtendedRequestHeader new_header{*old_header, 0};
+
// Requests are always a multiple of 4 bytes on the wire. Because of this,
// the length field represents the size in chunks of 4 bytes.
DCHECK_EQ(buf->size() % 4, 0UL);
- DCHECK_LE(buf->size() / 4, std::numeric_limits<uint16_t>::max());
- header->length = buf->size() / 4;
+ size_t size32 = buf->size() / 4;
+
+ struct iovec io[4];
+ memset(&io, 0, sizeof(io));
+ if (size32 < connection->setup().maximum_request_length) {
+ xpr.count = 1;
+ old_header->length = size32;
+ io[2].iov_base = buf->data();
+ io[2].iov_len = buf->size();
+ } else if (size32 < connection->extended_max_request_length()) {
+ xpr.count = 2;
+ DCHECK_EQ(new_header.header.length, 0U);
+ new_header.long_length = size32 + 1;
+ io[2].iov_base = &new_header;
+ io[2].iov_len = sizeof(ExtendedRequestHeader);
+ io[3].iov_base = buf->data() + sizeof(RequestHeader);
+ io[3].iov_len = buf->size() - sizeof(RequestHeader);
+ } else {
+ LOG(ERROR) << "Cannot send request of length " << buf->size();
+ return {nullptr, base::nullopt};
+ }
- struct iovec io[3];
- io[2].iov_base = buf->data();
- io[2].iov_len = buf->size();
+ xcb_connection_t* conn = connection->XcbConnection();
auto flags = XCB_REQUEST_CHECKED | XCB_REQUEST_RAW;
-
- xcb_connection_t* conn = XGetXCBConnection(display);
auto sequence = xcb_send_request(conn, flags, &io[2], &xpr);
if (xcb_connection_has_error(conn))
return {nullptr, base::nullopt};
- return {display, sequence};
+ return {connection, sequence};
}
// Helper function for xcbproto popcount. Given an integral type, returns the
@@ -143,19 +171,51 @@ bool CaseEq(T t, S s) {
return t == static_cast<decltype(t)>(s);
}
-// Helper function for xcbproto bitcase and & expressions. Checks if the
-// bitmasks |t| and |s| have any intersection.
+// Helper function for xcbproto bitcase expressions. Checks if the bitmasks |t|
+// and |s| have any intersection.
+template <typename T, typename S>
+bool CaseAnd(T t, S s) {
+ return static_cast<EnumBaseType<T>>(t) & static_cast<EnumBaseType<T>>(s);
+}
+
+// Helper function for xcbproto & expressions. Computes |t| & |s|.
template <typename T, typename S>
-bool BitAnd(T t, S s) {
+auto BitAnd(T t, S s) {
return static_cast<EnumBaseType<T>>(t) & static_cast<EnumBaseType<T>>(s);
}
-// Helper function for ~ expressions.
+// Helper function for xcbproto ~ expressions.
template <typename T>
-bool BitNot(T t) {
+auto BitNot(T t) {
return ~static_cast<EnumBaseType<T>>(t);
}
+// Helper function for generating switch values. |switch_var| is the value to
+// modify. |enum_val| is the value to set |switch_var| to if this is a regular
+// case, or the bit to be set in |switch_var| if this is a bit case. This
+// function is a no-op when |condition| is false.
+template <typename T>
+auto SwitchVar(T enum_val, bool condition, bool is_bitcase, T* switch_var) {
+ using EnumInt = EnumBaseType<T>;
+ if (!condition)
+ return;
+ EnumInt switch_int = static_cast<EnumInt>(*switch_var);
+ if (is_bitcase) {
+ *switch_var = static_cast<T>(switch_int | static_cast<EnumInt>(enum_val));
+ } else {
+ DCHECK(!switch_int);
+ *switch_var = enum_val;
+ }
+}
+
+template <typename T>
+std::unique_ptr<T> MakeExtension(Connection* connection,
+ Future<QueryExtensionReply> future) {
+ auto reply = future.Sync();
+ return std::make_unique<T>(connection,
+ reply ? *reply.reply : QueryExtensionReply{});
+}
+
} // namespace x11
#endif // UI_GFX_X_XPROTO_INTERNAL_H_