// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_GFX_X_XPROTO_INTERNAL_H_ #define UI_GFX_X_XPROTO_INTERNAL_H_ #ifndef IS_X11_IMPL #error "This file should only be included by //ui/gfx/x:xprotos" #endif #include #include #include "base/component_export.h" #include "base/logging.h" #include "base/memory/ref_counted_memory.h" #include "base/optional.h" #include "ui/gfx/x/connection.h" #include "ui/gfx/x/xproto_types.h" namespace x11 { template class Future; template struct EnumBase { using type = T; }; template struct EnumBase::value>> { using type = typename std::underlying_type::type; }; template using EnumBaseType = typename EnumBase::type; template void ReadError(T* error, ReadBuffer* buf); // Calls free() on the underlying data when the count drops to 0. class COMPONENT_EXPORT(X11) MallocedRefCountedMemory : public base::RefCountedMemory { public: explicit MallocedRefCountedMemory(void* data); MallocedRefCountedMemory(const MallocedRefCountedMemory&) = delete; MallocedRefCountedMemory& operator=(const MallocedRefCountedMemory&) = delete; const uint8_t* front() const override; size_t size() const override; private: ~MallocedRefCountedMemory() override; uint8_t* const data_; }; // Wraps another RefCountedMemory, giving a view into it. Similar to // base::StringPiece, the data is some contiguous subarray, but unlike // StringPiece, a counted reference is kept on the underlying memory. class COMPONENT_EXPORT(X11) OffsetRefCountedMemory : public base::RefCountedMemory { public: OffsetRefCountedMemory(scoped_refptr memory, size_t offset, size_t size); OffsetRefCountedMemory(const OffsetRefCountedMemory&) = delete; OffsetRefCountedMemory& operator=(const OffsetRefCountedMemory&) = delete; const uint8_t* front() const override; size_t size() const override; private: ~OffsetRefCountedMemory() override; scoped_refptr memory_; size_t offset_; size_t size_; }; // Wraps a bare pointer and does not take any action when the reference count // reaches 0. This is used to wrap stack-alloctaed or persistent data so we can // pass those to Read/ReadEvent/ReadReply which expect RefCountedMemory. class COMPONENT_EXPORT(X11) UnretainedRefCountedMemory : public base::RefCountedMemory { public: explicit UnretainedRefCountedMemory(const void* data); UnretainedRefCountedMemory(const UnretainedRefCountedMemory&) = delete; UnretainedRefCountedMemory& operator=(const UnretainedRefCountedMemory&) = delete; const uint8_t* front() const override; size_t size() const override; private: ~UnretainedRefCountedMemory() override; const uint8_t* const data_; }; template void Read(T* t, ReadBuffer* buf) { static_assert(std::is_trivially_copyable::value, ""); detail::VerifyAlignment(t, buf->offset); memcpy(t, buf->data->data() + buf->offset, sizeof(*t)); buf->offset += sizeof(*t); } inline void Pad(WriteBuffer* buf, size_t amount) { uint8_t zero = 0; for (size_t i = 0; i < amount; i++) buf->Write(&zero); } inline void Pad(ReadBuffer* buf, size_t amount) { buf->offset += amount; } inline void Align(WriteBuffer* buf, size_t align) { Pad(buf, (align - (buf->offset() % align)) % align); } inline void Align(ReadBuffer* buf, size_t align) { Pad(buf, (align - (buf->offset % align)) % align); } base::Optional SendRequestImpl(x11::Connection* connection, WriteBuffer* buf, bool is_void, bool reply_has_fds); template Future SendRequest(x11::Connection* connection, WriteBuffer* buf, bool reply_has_fds, const char* request_name) { auto sequence = SendRequestImpl(connection, buf, std::is_void::value, reply_has_fds); return {sequence ? connection : nullptr, sequence, sequence ? request_name : nullptr}; } // Helper function for xcbproto popcount. Given an integral type, returns the // number of 1 bits present. template size_t PopCount(T t) { return std::bitset(static_cast>(t)).count(); } // Helper function for xcbproto sumof. Given a function |f| and a container // |t|, maps the elements uisng |f| and reduces by summing the results. template auto SumOf(F&& f, T& t) { decltype(f(t[0])) sum = 0; for (auto& v : t) sum += f(v); return sum; } // Helper function for xcbproto case. Checks for equality between |t| and |s|. template bool CaseEq(T t, S s) { return t == static_cast(s); } // Helper function for xcbproto bitcase expressions. Checks if the bitmasks |t| // and |s| have any intersection. template bool CaseAnd(T t, S s) { return static_cast>(t) & static_cast>(s); } // Helper function for xcbproto & expressions. Computes |t| & |s|. template auto BitAnd(T t, S s) { return static_cast>(t) & static_cast>(s); } // Helper function for xcbproto ~ expressions. template auto BitNot(T t) { return ~static_cast>(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 auto SwitchVar(T enum_val, bool condition, bool is_bitcase, T* switch_var) { using EnumInt = EnumBaseType; if (!condition) return; EnumInt switch_int = static_cast(*switch_var); if (is_bitcase) { *switch_var = static_cast(switch_int | static_cast(enum_val)); } else { DCHECK(!switch_int); *switch_var = enum_val; } } template std::unique_ptr MakeExtension(Connection* connection, Future future) { auto reply = future.Sync(); return std::make_unique(connection, reply ? *reply.reply : QueryExtensionReply{}); } } // namespace x11 #endif // UI_GFX_X_XPROTO_INTERNAL_H_