diff options
Diffstat (limited to 'chromium/ui/gfx/x/xproto_internal.h')
-rw-r--r-- | chromium/ui/gfx/x/xproto_internal.h | 104 |
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_ |