/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_TYPES_H_ #define MOZILLA_GFX_TYPES_H_ #include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM_CLASS_WITH_BASE #include "mozilla/EndianUtils.h" #include "mozilla/EnumeratedRange.h" #include "mozilla/MacroArgs.h" // for MOZ_CONCAT #include "mozilla/TypedEnumBits.h" #include // for ostream #include #include #include namespace mozilla { namespace gfx { typedef float Float; typedef double Double; enum class SurfaceType : int8_t { DATA, /* Data surface - bitmap in memory */ D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */ D2D1_DRAWTARGET, /* Surface made from a D2D draw target */ CAIRO, /* Surface wrapping a cairo surface */ CAIRO_IMAGE, /* Data surface wrapping a cairo image surface */ COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */ COREGRAPHICS_CGCONTEXT, /* Surface wrapping a CG context */ SKIA, /* Surface wrapping a Skia bitmap */ D2D1_1_IMAGE, /* A D2D 1.1 ID2D1Image SourceSurface */ RECORDING, /* Surface used for recording */ DATA_SHARED, /* Data surface using shared memory */ DATA_RECYCLING_SHARED, /* Data surface using shared memory */ OFFSET, /* Offset */ DATA_ALIGNED, /* Data surface using aligned heap memory */ DATA_SHARED_WRAPPER, /* Shared memory mapped in from another process */ BLOB_IMAGE, /* Recorded blob image */ DATA_MAPPED, /* Data surface wrapping a ScopedMap */ WEBGL, /* Surface wrapping a DrawTargetWebgl texture */ }; enum class SurfaceFormat : int8_t { // The following values are named to reflect layout of colors in memory, from // lowest byte to highest byte. The 32-bit value layout depends on machine // endianness. // in-memory 32-bit LE value 32-bit BE value B8G8R8A8, // [BB, GG, RR, AA] 0xAARRGGBB 0xBBGGRRAA B8G8R8X8, // [BB, GG, RR, 00] 0x00RRGGBB 0xBBGGRR00 R8G8B8A8, // [RR, GG, BB, AA] 0xAABBGGRR 0xRRGGBBAA R8G8B8X8, // [RR, GG, BB, 00] 0x00BBGGRR 0xRRGGBB00 A8R8G8B8, // [AA, RR, GG, BB] 0xBBGGRRAA 0xAARRGGBB X8R8G8B8, // [00, RR, GG, BB] 0xBBGGRR00 0x00RRGGBB R8G8B8, B8G8R8, // The _UINT16 suffix here indicates that the name reflects the layout when // viewed as a uint16_t value. In memory these values are stored using native // endianness. R5G6B5_UINT16, // 0bRRRRRGGGGGGBBBBB // This one is a single-byte, so endianness isn't an issue. A8, A16, R8G8, R16G16, // These ones are their own special cases. YUV, NV12, // YUV 4:2:0 image with a plane of 8 bit Y samples followed by // an interleaved U/V plane containing 8 bit 2x2 subsampled // colour difference samples. P016, // Similar to NV12, but with 16 bits plane values P010, // Identical to P016 but the 6 least significant bits are 0. // With DXGI in theory entirely compatible, however practice has // shown that it's not the case. YUV422, // Single plane YUV 4:2:2 interleaved as Y`0 Cb Y`1 Cr. HSV, Lab, Depth, // This represents the unknown format. UNKNOWN, // TODO: Replace uses with Maybe. // The following values are endian-independent synonyms. The _UINT32 suffix // indicates that the name reflects the layout when viewed as a uint32_t // value. #if MOZ_LITTLE_ENDIAN() A8R8G8B8_UINT32 = B8G8R8A8, // 0xAARRGGBB X8R8G8B8_UINT32 = B8G8R8X8, // 0x00RRGGBB #elif MOZ_BIG_ENDIAN() A8R8G8B8_UINT32 = A8R8G8B8, // 0xAARRGGBB X8R8G8B8_UINT32 = X8R8G8B8, // 0x00RRGGBB #else # error "bad endianness" #endif // The following values are OS and endian-independent synonyms. // // TODO(aosmond): When everything blocking bug 1581828 has been resolved, we // can make this use R8B8G8A8 and R8B8G8X8 for non-Windows platforms. OS_RGBA = A8R8G8B8_UINT32, OS_RGBX = X8R8G8B8_UINT32 }; struct SurfaceFormatInfo { bool hasColor; bool hasAlpha; bool isYuv; std::optional bytesPerPixel; }; inline std::optional Info(const SurfaceFormat aFormat) { auto info = SurfaceFormatInfo{}; switch (aFormat) { case SurfaceFormat::B8G8R8A8: case SurfaceFormat::R8G8B8A8: case SurfaceFormat::A8R8G8B8: info.hasColor = true; info.hasAlpha = true; break; case SurfaceFormat::B8G8R8X8: case SurfaceFormat::R8G8B8X8: case SurfaceFormat::X8R8G8B8: case SurfaceFormat::R8G8B8: case SurfaceFormat::B8G8R8: case SurfaceFormat::R5G6B5_UINT16: case SurfaceFormat::R8G8: case SurfaceFormat::R16G16: case SurfaceFormat::HSV: case SurfaceFormat::Lab: info.hasColor = true; info.hasAlpha = false; break; case SurfaceFormat::A8: case SurfaceFormat::A16: info.hasColor = false; info.hasAlpha = true; break; case SurfaceFormat::YUV: case SurfaceFormat::NV12: case SurfaceFormat::P016: case SurfaceFormat::P010: case SurfaceFormat::YUV422: info.hasColor = true; info.hasAlpha = false; info.isYuv = true; break; case SurfaceFormat::Depth: info.hasColor = false; info.hasAlpha = false; info.isYuv = false; break; case SurfaceFormat::UNKNOWN: break; } // - // bytesPerPixel switch (aFormat) { case SurfaceFormat::B8G8R8A8: case SurfaceFormat::R8G8B8A8: case SurfaceFormat::A8R8G8B8: case SurfaceFormat::B8G8R8X8: case SurfaceFormat::R8G8B8X8: case SurfaceFormat::X8R8G8B8: case SurfaceFormat::R16G16: info.bytesPerPixel = 4; break; case SurfaceFormat::R8G8B8: case SurfaceFormat::B8G8R8: info.bytesPerPixel = 3; break; case SurfaceFormat::R5G6B5_UINT16: case SurfaceFormat::R8G8: case SurfaceFormat::A16: case SurfaceFormat::Depth: // uint16_t info.bytesPerPixel = 2; break; case SurfaceFormat::A8: info.bytesPerPixel = 1; break; case SurfaceFormat::HSV: case SurfaceFormat::Lab: info.bytesPerPixel = 3 * sizeof(float); break; case SurfaceFormat::YUV: case SurfaceFormat::NV12: case SurfaceFormat::P016: case SurfaceFormat::P010: case SurfaceFormat::YUV422: case SurfaceFormat::UNKNOWN: break; // No bytesPerPixel per se. } // - if (aFormat == SurfaceFormat::UNKNOWN) { return {}; } return info; } std::ostream& operator<<(std::ostream& aOut, const SurfaceFormat& aFormat); // Represents the bit-shifts required to access color channels when the layout // is viewed as a uint32_t value. enum class SurfaceFormatBit : uint32_t { #if MOZ_LITTLE_ENDIAN() R8G8B8A8_R = 0, R8G8B8A8_G = 8, R8G8B8A8_B = 16, R8G8B8A8_A = 24, #elif MOZ_BIG_ENDIAN() R8G8B8A8_A = 0, R8G8B8A8_B = 8, R8G8B8A8_G = 16, R8G8B8A8_R = 24, #else # error "bad endianness" #endif // The following values are endian-independent for A8R8G8B8_UINT32. A8R8G8B8_UINT32_B = 0, A8R8G8B8_UINT32_G = 8, A8R8G8B8_UINT32_R = 16, A8R8G8B8_UINT32_A = 24, // The following values are OS and endian-independent. // // TODO(aosmond): When everything blocking bug 1581828 has been resolved, we // can make this use R8G8B8A8_X for non-Windows platforms. OS_R = A8R8G8B8_UINT32_R, OS_G = A8R8G8B8_UINT32_G, OS_B = A8R8G8B8_UINT32_B, OS_A = A8R8G8B8_UINT32_A, }; inline uint32_t operator<<(uint8_t a, SurfaceFormatBit b) { return a << static_cast(b); } inline uint32_t operator>>(uint32_t a, SurfaceFormatBit b) { return a >> static_cast(b); } static inline int BytesPerPixel(SurfaceFormat aFormat) { // TODO: return Info(aFormat).value().bytesPerPixel.value(); switch (aFormat) { case SurfaceFormat::A8: return 1; case SurfaceFormat::R5G6B5_UINT16: case SurfaceFormat::A16: return 2; case SurfaceFormat::R8G8B8: case SurfaceFormat::B8G8R8: return 3; case SurfaceFormat::HSV: case SurfaceFormat::Lab: return 3 * sizeof(float); case SurfaceFormat::Depth: return sizeof(uint16_t); default: return 4; } } inline bool IsOpaque(SurfaceFormat aFormat) { // TODO: return Info(aFormat).value().hasAlpha; switch (aFormat) { case SurfaceFormat::B8G8R8X8: case SurfaceFormat::R8G8B8X8: case SurfaceFormat::X8R8G8B8: case SurfaceFormat::R5G6B5_UINT16: case SurfaceFormat::R8G8B8: case SurfaceFormat::B8G8R8: case SurfaceFormat::R8G8: case SurfaceFormat::HSV: case SurfaceFormat::Lab: case SurfaceFormat::Depth: case SurfaceFormat::YUV: case SurfaceFormat::NV12: case SurfaceFormat::P010: case SurfaceFormat::P016: case SurfaceFormat::YUV422: return true; default: return false; } } // These are standardized Coding-independent Code Points // See [Rec. ITU-T H.273 // (12/2016)](https://www.itu.int/rec/T-REC-H.273-201612-I/en) // // We deliberately use an unscoped enum with fixed uint8_t representation since // all possible values [0, 255] are legal, but it's unwieldy to declare 200+ // "RESERVED" enumeration values. Having a fixed underlying type avoids any // potential UB and avoids the need for a cast when passing these values across // FFI to functions like qcms_profile_create_cicp. namespace CICP { enum ColourPrimaries : uint8_t { CP_RESERVED_MIN = 0, // 0, 3, [13, 21], [23, 255] are all reserved CP_BT709 = 1, CP_UNSPECIFIED = 2, CP_BT470M = 4, CP_BT470BG = 5, CP_BT601 = 6, CP_SMPTE240 = 7, CP_GENERIC_FILM = 8, CP_BT2020 = 9, CP_XYZ = 10, CP_SMPTE431 = 11, CP_SMPTE432 = 12, CP_EBU3213 = 22, }; inline bool IsReserved(ColourPrimaries aIn) { switch (aIn) { case CP_BT709: case CP_UNSPECIFIED: case CP_BT470M: case CP_BT470BG: case CP_BT601: case CP_SMPTE240: case CP_GENERIC_FILM: case CP_BT2020: case CP_XYZ: case CP_SMPTE431: case CP_SMPTE432: case CP_EBU3213: return false; default: return true; } } enum TransferCharacteristics : uint8_t { TC_RESERVED_MIN = 0, // 0, 3, [19, 255] are all reserved TC_BT709 = 1, TC_UNSPECIFIED = 2, TC_BT470M = 4, TC_BT470BG = 5, TC_BT601 = 6, TC_SMPTE240 = 7, TC_LINEAR = 8, TC_LOG_100 = 9, TC_LOG_100_SQRT10 = 10, TC_IEC61966 = 11, TC_BT_1361 = 12, TC_SRGB = 13, TC_BT2020_10BIT = 14, TC_BT2020_12BIT = 15, TC_SMPTE2084 = 16, TC_SMPTE428 = 17, TC_HLG = 18, }; inline bool IsReserved(TransferCharacteristics aIn) { switch (aIn) { case TC_BT709: case TC_UNSPECIFIED: case TC_BT470M: case TC_BT470BG: case TC_BT601: case TC_SMPTE240: case TC_LINEAR: case TC_LOG_100: case TC_LOG_100_SQRT10: case TC_IEC61966: case TC_BT_1361: case TC_SRGB: case TC_BT2020_10BIT: case TC_BT2020_12BIT: case TC_SMPTE2084: case TC_SMPTE428: case TC_HLG: return false; default: return true; } } enum MatrixCoefficients : uint8_t { MC_IDENTITY = 0, MC_BT709 = 1, MC_UNSPECIFIED = 2, MC_RESERVED_MIN = 3, // 3, [15, 255] are all reserved MC_FCC = 4, MC_BT470BG = 5, MC_BT601 = 6, MC_SMPTE240 = 7, MC_YCGCO = 8, MC_BT2020_NCL = 9, MC_BT2020_CL = 10, MC_SMPTE2085 = 11, MC_CHROMAT_NCL = 12, MC_CHROMAT_CL = 13, MC_ICTCP = 14, }; inline bool IsReserved(MatrixCoefficients aIn) { switch (aIn) { case MC_IDENTITY: case MC_BT709: case MC_UNSPECIFIED: case MC_RESERVED_MIN: case MC_FCC: case MC_BT470BG: case MC_BT601: case MC_SMPTE240: case MC_YCGCO: case MC_BT2020_NCL: case MC_BT2020_CL: case MC_SMPTE2085: case MC_CHROMAT_NCL: case MC_CHROMAT_CL: case MC_ICTCP: return false; default: return true; } } } // namespace CICP // The matrix coeffiecients used for YUV to RGB conversion. enum class YUVColorSpace : uint8_t { BT601, BT709, BT2020, Identity, // Todo: s/YUVColorSpace/ColorSpace/, s/Identity/SRGB/ Default = BT709, _First = BT601, _Last = Identity, }; enum class ColorDepth : uint8_t { COLOR_8, COLOR_10, COLOR_12, COLOR_16, _First = COLOR_8, _Last = COLOR_16, }; enum class TransferFunction : uint8_t { BT709, SRGB, PQ, HLG, _First = BT709, _Last = HLG, Default = BT709, }; enum class ColorRange : uint8_t { LIMITED, FULL, _First = LIMITED, _Last = FULL, }; // Really "YcbcrColorColorSpace" enum class YUVRangedColorSpace : uint8_t { BT601_Narrow = 0, BT601_Full, BT709_Narrow, BT709_Full, BT2020_Narrow, BT2020_Full, GbrIdentity, _First = BT601_Narrow, _Last = GbrIdentity, Default = BT709_Narrow, }; // I can either come up with a longer "very clever" name that doesn't conflict // with FilterSupport.h, embrace and expand FilterSupport, or rename the old // one. // Some times Worse Is Better. enum class ColorSpace2 : uint8_t { Display, UNKNOWN = Display, // We feel sufficiently bad about this TODO. SRGB, DISPLAY_P3, BT601_525, // aka smpte170m NTSC BT709, // Same gamut as SRGB, but different gamma. BT601_625 = BT709, // aka bt470bg PAL. Basically BT709, just Xg is 0.290 not 0.300. BT2020, _First = Display, _Last = BT2020, }; inline ColorSpace2 ToColorSpace2(const YUVColorSpace in) { switch (in) { case YUVColorSpace::BT601: return ColorSpace2::BT601_525; case YUVColorSpace::BT709: return ColorSpace2::BT709; case YUVColorSpace::BT2020: return ColorSpace2::BT2020; case YUVColorSpace::Identity: return ColorSpace2::SRGB; } MOZ_ASSERT_UNREACHABLE(); } inline YUVColorSpace ToYUVColorSpace(const ColorSpace2 in) { switch (in) { case ColorSpace2::BT601_525: return YUVColorSpace::BT601; case ColorSpace2::BT709: return YUVColorSpace::BT709; case ColorSpace2::BT2020: return YUVColorSpace::BT2020; case ColorSpace2::SRGB: return YUVColorSpace::Identity; case ColorSpace2::UNKNOWN: case ColorSpace2::DISPLAY_P3: MOZ_CRASH("Bad ColorSpace2 for ToYUVColorSpace"); } MOZ_ASSERT_UNREACHABLE(); } struct FromYUVRangedColorSpaceT final { const YUVColorSpace space; const ColorRange range; }; inline FromYUVRangedColorSpaceT FromYUVRangedColorSpace( const YUVRangedColorSpace s) { switch (s) { case YUVRangedColorSpace::BT601_Narrow: return {YUVColorSpace::BT601, ColorRange::LIMITED}; case YUVRangedColorSpace::BT601_Full: return {YUVColorSpace::BT601, ColorRange::FULL}; case YUVRangedColorSpace::BT709_Narrow: return {YUVColorSpace::BT709, ColorRange::LIMITED}; case YUVRangedColorSpace::BT709_Full: return {YUVColorSpace::BT709, ColorRange::FULL}; case YUVRangedColorSpace::BT2020_Narrow: return {YUVColorSpace::BT2020, ColorRange::LIMITED}; case YUVRangedColorSpace::BT2020_Full: return {YUVColorSpace::BT2020, ColorRange::FULL}; case YUVRangedColorSpace::GbrIdentity: return {YUVColorSpace::Identity, ColorRange::FULL}; } MOZ_CRASH("bad YUVRangedColorSpace"); } // Todo: This should go in the CPP. inline YUVRangedColorSpace ToYUVRangedColorSpace(const YUVColorSpace space, const ColorRange range) { bool narrow; switch (range) { case ColorRange::FULL: narrow = false; break; case ColorRange::LIMITED: narrow = true; break; } switch (space) { case YUVColorSpace::Identity: MOZ_ASSERT(range == ColorRange::FULL); return YUVRangedColorSpace::GbrIdentity; case YUVColorSpace::BT601: return narrow ? YUVRangedColorSpace::BT601_Narrow : YUVRangedColorSpace::BT601_Full; case YUVColorSpace::BT709: return narrow ? YUVRangedColorSpace::BT709_Narrow : YUVRangedColorSpace::BT709_Full; case YUVColorSpace::BT2020: return narrow ? YUVRangedColorSpace::BT2020_Narrow : YUVRangedColorSpace::BT2020_Full; } MOZ_CRASH("bad YUVColorSpace"); } template inline YUVRangedColorSpace GetYUVRangedColorSpace(const DescriptorT& d) { return ToYUVRangedColorSpace(d.yUVColorSpace(), d.colorRange()); } static inline SurfaceFormat SurfaceFormatForColorDepth(ColorDepth aColorDepth) { SurfaceFormat format = SurfaceFormat::A8; switch (aColorDepth) { case ColorDepth::COLOR_8: break; case ColorDepth::COLOR_10: case ColorDepth::COLOR_12: case ColorDepth::COLOR_16: format = SurfaceFormat::A16; break; } return format; } static inline uint8_t BitDepthForColorDepth(ColorDepth aColorDepth) { uint8_t depth = 8; switch (aColorDepth) { case ColorDepth::COLOR_8: break; case ColorDepth::COLOR_10: depth = 10; break; case ColorDepth::COLOR_12: depth = 12; break; case ColorDepth::COLOR_16: depth = 16; break; } return depth; } static inline ColorDepth ColorDepthForBitDepth(uint8_t aBitDepth) { ColorDepth depth = ColorDepth::COLOR_8; switch (aBitDepth) { case 8: break; case 10: depth = ColorDepth::COLOR_10; break; case 12: depth = ColorDepth::COLOR_12; break; case 16: depth = ColorDepth::COLOR_16; break; } return depth; } // 10 and 12 bits color depth image are using 16 bits integers for storage // As such we need to rescale the value from 10 or 12 bits to 16. static inline uint32_t RescalingFactorForColorDepth(ColorDepth aColorDepth) { uint32_t factor = 1; switch (aColorDepth) { case ColorDepth::COLOR_8: break; case ColorDepth::COLOR_10: factor = 64; break; case ColorDepth::COLOR_12: factor = 16; break; case ColorDepth::COLOR_16: break; } return factor; } enum class ChromaSubsampling : uint8_t { FULL, HALF_WIDTH, HALF_WIDTH_AND_HEIGHT, _First = FULL, _Last = HALF_WIDTH_AND_HEIGHT, }; template static inline T ChromaSize(const T& aYSize, ChromaSubsampling aSubsampling) { switch (aSubsampling) { case ChromaSubsampling::FULL: return aYSize; case ChromaSubsampling::HALF_WIDTH: return T((aYSize.width + 1) / 2, aYSize.height); case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT: return T((aYSize.width + 1) / 2, (aYSize.height + 1) / 2); } MOZ_CRASH("bad ChromaSubsampling"); } enum class FilterType : int8_t { BLEND = 0, TRANSFORM, MORPHOLOGY, COLOR_MATRIX, FLOOD, TILE, TABLE_TRANSFER, DISCRETE_TRANSFER, LINEAR_TRANSFER, GAMMA_TRANSFER, CONVOLVE_MATRIX, DISPLACEMENT_MAP, TURBULENCE, ARITHMETIC_COMBINE, COMPOSITE, DIRECTIONAL_BLUR, GAUSSIAN_BLUR, POINT_DIFFUSE, POINT_SPECULAR, SPOT_DIFFUSE, SPOT_SPECULAR, DISTANT_DIFFUSE, DISTANT_SPECULAR, CROP, PREMULTIPLY, UNPREMULTIPLY, OPACITY }; enum class DrawTargetType : int8_t { SOFTWARE_RASTER = 0, HARDWARE_RASTER, VECTOR }; enum class BackendType : int8_t { NONE = 0, DIRECT2D, // Used for version independent D2D objects. CAIRO, SKIA, RECORDING, DIRECT2D1_1, WEBRENDER_TEXT, WEBGL, // Add new entries above this line. BACKEND_LAST }; enum class FontType : int8_t { DWRITE, GDI, MAC, FONTCONFIG, FREETYPE, UNKNOWN }; enum class NativeSurfaceType : int8_t { D3D10_TEXTURE, CAIRO_CONTEXT, CGCONTEXT, CGCONTEXT_ACCELERATED, OPENGL_TEXTURE, WEBGL_CONTEXT }; enum class FontStyle : int8_t { NORMAL, ITALIC, BOLD, BOLD_ITALIC }; enum class FontHinting : int8_t { NONE, LIGHT, NORMAL, FULL }; enum class CompositionOp : int8_t { OP_CLEAR, OP_OVER, OP_ADD, OP_ATOP, OP_OUT, OP_IN, OP_SOURCE, OP_DEST_IN, OP_DEST_OUT, OP_DEST_OVER, OP_DEST_ATOP, OP_XOR, OP_MULTIPLY, OP_SCREEN, OP_OVERLAY, OP_DARKEN, OP_LIGHTEN, OP_COLOR_DODGE, OP_COLOR_BURN, OP_HARD_LIGHT, OP_SOFT_LIGHT, OP_DIFFERENCE, OP_EXCLUSION, OP_HUE, OP_SATURATION, OP_COLOR, OP_LUMINOSITY, OP_COUNT }; enum class Axis : int8_t { X_AXIS, Y_AXIS, BOTH }; enum class ExtendMode : int8_t { CLAMP, // Do not repeat REPEAT, // Repeat in both axis REPEAT_X, // Only X axis REPEAT_Y, // Only Y axis REFLECT // Mirror the image }; enum class FillRule : int8_t { FILL_WINDING, FILL_EVEN_ODD }; enum class AntialiasMode : int8_t { NONE, GRAY, SUBPIXEL, DEFAULT }; // See https://en.wikipedia.org/wiki/Texture_filtering enum class SamplingFilter : int8_t { GOOD, LINEAR, POINT, SENTINEL // one past the last valid value }; std::ostream& operator<<(std::ostream& aOut, const SamplingFilter& aFilter); // clang-format off MOZ_DEFINE_ENUM_CLASS_WITH_BASE(PatternType, int8_t, ( COLOR, SURFACE, LINEAR_GRADIENT, RADIAL_GRADIENT, CONIC_GRADIENT )); // clang-format on enum class JoinStyle : int8_t { BEVEL, ROUND, MITER, //!< Mitered if within the miter limit, else, if the backed supports //!< it (D2D), the miter is clamped. If the backend does not support //!< miter clamping the behavior is as for MITER_OR_BEVEL. MITER_OR_BEVEL //!< Mitered if within the miter limit, else beveled. }; enum class CapStyle : int8_t { BUTT, ROUND, SQUARE }; enum class SamplingBounds : int8_t { UNBOUNDED, BOUNDED }; // Moz2d version for SVG mask types enum class LuminanceType : int8_t { LUMINANCE, LINEARRGB, }; /* Color is stored in non-premultiplied form in sRGB color space */ struct sRGBColor { public: constexpr sRGBColor() : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {} constexpr sRGBColor(Float aR, Float aG, Float aB, Float aA) : r(aR), g(aG), b(aB), a(aA) {} constexpr sRGBColor(Float aR, Float aG, Float aB) : r(aR), g(aG), b(aB), a(1.0f) {} static constexpr sRGBColor White(float aA) { return sRGBColor(1.f, 1.f, 1.f, aA); } static constexpr sRGBColor Black(float aA) { return sRGBColor(0.f, 0.f, 0.f, aA); } static constexpr sRGBColor OpaqueWhite() { return White(1.f); } static constexpr sRGBColor OpaqueBlack() { return Black(1.f); } static constexpr sRGBColor FromU8(uint8_t aR, uint8_t aG, uint8_t aB, uint8_t aA) { return sRGBColor(float(aR) / 255.f, float(aG) / 255.f, float(aB) / 255.f, float(aA) / 255.f); } static constexpr sRGBColor FromABGR(uint32_t aColor) { return sRGBColor(((aColor >> 0) & 0xff) * (1.0f / 255.0f), ((aColor >> 8) & 0xff) * (1.0f / 255.0f), ((aColor >> 16) & 0xff) * (1.0f / 255.0f), ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); } // The "Unusual" prefix is to avoid unintentionally using this function when // FromABGR(), which is much more common, is needed. static constexpr sRGBColor UnusualFromARGB(uint32_t aColor) { return sRGBColor(((aColor >> 16) & 0xff) * (1.0f / 255.0f), ((aColor >> 8) & 0xff) * (1.0f / 255.0f), ((aColor >> 0) & 0xff) * (1.0f / 255.0f), ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); } constexpr uint32_t ToABGR() const { return uint32_t(r * 255.0f) | uint32_t(g * 255.0f) << 8 | uint32_t(b * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; } constexpr sRGBColor Premultiplied() const { return sRGBColor(r * a, g * a, b * a, a); } constexpr sRGBColor Unpremultiplied() const { return a > 0.f ? sRGBColor(r / a, g / a, b / a, a) : *this; } // The "Unusual" prefix is to avoid unintentionally using this function when // ToABGR(), which is much more common, is needed. uint32_t UnusualToARGB() const { return uint32_t(b * 255.0f) | uint32_t(g * 255.0f) << 8 | uint32_t(r * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; } bool operator==(const sRGBColor& aColor) const { return r == aColor.r && g == aColor.g && b == aColor.b && a == aColor.a; } bool operator!=(const sRGBColor& aColor) const { return !(*this == aColor); } Float r, g, b, a; }; /* Color is stored in non-premultiplied form in device color space */ struct DeviceColor { public: DeviceColor() : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {} DeviceColor(Float aR, Float aG, Float aB, Float aA) : r(aR), g(aG), b(aB), a(aA) {} DeviceColor(Float aR, Float aG, Float aB) : r(aR), g(aG), b(aB), a(1.0f) {} /* The following Mask* variants are helpers used to make it clear when a * particular color is being used for masking purposes. These masks should * never be colored managed. */ static DeviceColor Mask(float aC, float aA) { return DeviceColor(aC, aC, aC, aA); } static DeviceColor MaskWhite(float aA) { return Mask(1.f, aA); } static DeviceColor MaskBlack(float aA) { return Mask(0.f, aA); } static DeviceColor MaskOpaqueWhite() { return MaskWhite(1.f); } static DeviceColor MaskOpaqueBlack() { return MaskBlack(1.f); } static DeviceColor FromU8(uint8_t aR, uint8_t aG, uint8_t aB, uint8_t aA) { return DeviceColor(float(aR) / 255.f, float(aG) / 255.f, float(aB) / 255.f, float(aA) / 255.f); } static DeviceColor FromABGR(uint32_t aColor) { DeviceColor newColor(((aColor >> 0) & 0xff) * (1.0f / 255.0f), ((aColor >> 8) & 0xff) * (1.0f / 255.0f), ((aColor >> 16) & 0xff) * (1.0f / 255.0f), ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); return newColor; } // The "Unusual" prefix is to avoid unintentionally using this function when // FromABGR(), which is much more common, is needed. static DeviceColor UnusualFromARGB(uint32_t aColor) { DeviceColor newColor(((aColor >> 16) & 0xff) * (1.0f / 255.0f), ((aColor >> 8) & 0xff) * (1.0f / 255.0f), ((aColor >> 0) & 0xff) * (1.0f / 255.0f), ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); return newColor; } uint32_t ToABGR() const { return uint32_t(r * 255.0f) | uint32_t(g * 255.0f) << 8 | uint32_t(b * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; } // The "Unusual" prefix is to avoid unintentionally using this function when // ToABGR(), which is much more common, is needed. uint32_t UnusualToARGB() const { return uint32_t(b * 255.0f) | uint32_t(g * 255.0f) << 8 | uint32_t(r * 255.0f) << 16 | uint32_t(a * 255.0f) << 24; } bool operator==(const DeviceColor& aColor) const { return r == aColor.r && g == aColor.g && b == aColor.b && a == aColor.a; } bool operator!=(const DeviceColor& aColor) const { return !(*this == aColor); } friend std::ostream& operator<<(std::ostream& aOut, const DeviceColor& aColor); Float r, g, b, a; }; struct GradientStop { bool operator<(const GradientStop& aOther) const { return offset < aOther.offset; } Float offset; DeviceColor color; }; enum class JobStatus { Complete, Wait, Yield, Error }; } // namespace gfx } // namespace mozilla // XXX: temporary typedef mozilla::gfx::SurfaceFormat gfxImageFormat; #if defined(XP_WIN) && defined(MOZ_GFX) # ifdef GFX2D_INTERNAL # define GFX2D_API __declspec(dllexport) # else # define GFX2D_API __declspec(dllimport) # endif #else # define GFX2D_API #endif namespace mozilla { // Side constants for use in various places. enum Side : uint8_t { eSideTop, eSideRight, eSideBottom, eSideLeft }; std::ostream& operator<<(std::ostream&, const mozilla::Side&); constexpr auto AllPhysicalSides() { return mozilla::MakeInclusiveEnumeratedRange(eSideTop, eSideLeft); } enum class SideBits { eNone = 0, eTop = 1 << eSideTop, eRight = 1 << eSideRight, eBottom = 1 << eSideBottom, eLeft = 1 << eSideLeft, eTopBottom = SideBits::eTop | SideBits::eBottom, eLeftRight = SideBits::eLeft | SideBits::eRight, eAll = SideBits::eTopBottom | SideBits::eLeftRight }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SideBits) inline constexpr SideBits SideToSideBit(mozilla::Side aSide) { return SideBits(1 << aSide); } enum Corner : uint8_t { // This order is important! eCornerTopLeft = 0, eCornerTopRight = 1, eCornerBottomRight = 2, eCornerBottomLeft = 3 }; // RectCornerRadii::radii depends on this value. It is not being added to // Corner because we want to lift the responsibility to handle it in the // switch-case. constexpr int eCornerCount = 4; constexpr auto AllPhysicalCorners() { return mozilla::MakeInclusiveEnumeratedRange(eCornerTopLeft, eCornerBottomLeft); } // Indices into "half corner" arrays (nsStyleCorners e.g.) enum HalfCorner : uint8_t { // This order is important! eCornerTopLeftX = 0, eCornerTopLeftY = 1, eCornerTopRightX = 2, eCornerTopRightY = 3, eCornerBottomRightX = 4, eCornerBottomRightY = 5, eCornerBottomLeftX = 6, eCornerBottomLeftY = 7 }; constexpr auto AllPhysicalHalfCorners() { return mozilla::MakeInclusiveEnumeratedRange(eCornerTopLeftX, eCornerBottomLeftY); } // The result of these conversion functions are exhaustively checked in // nsFrame.cpp, which also serves as usage examples. constexpr bool HalfCornerIsX(HalfCorner aHalfCorner) { return !(aHalfCorner % 2); } constexpr Corner HalfToFullCorner(HalfCorner aHalfCorner) { return Corner(aHalfCorner / 2); } constexpr HalfCorner FullToHalfCorner(Corner aCorner, bool aIsVertical) { return HalfCorner(aCorner * 2 + aIsVertical); } constexpr bool SideIsVertical(mozilla::Side aSide) { return aSide % 2; } // @param aIsSecond when true, return the clockwise second of the two // corners associated with aSide. For example, with aSide = eSideBottom the // result is eCornerBottomRight when aIsSecond is false, and // eCornerBottomLeft when aIsSecond is true. constexpr Corner SideToFullCorner(mozilla::Side aSide, bool aIsSecond) { return Corner((aSide + aIsSecond) % 4); } // @param aIsSecond see SideToFullCorner. // @param aIsParallel return the half-corner that is parallel with aSide // when aIsParallel is true. For example with aSide=eSideTop, aIsSecond=true // the result is eCornerTopRightX when aIsParallel is true, and // eCornerTopRightY when aIsParallel is false (because "X" is parallel with // eSideTop/eSideBottom, similarly "Y" is parallel with // eSideLeft/eSideRight) constexpr HalfCorner SideToHalfCorner(mozilla::Side aSide, bool aIsSecond, bool aIsParallel) { return HalfCorner(((aSide + aIsSecond) * 2 + (aSide + !aIsParallel) % 2) % 8); } } // namespace mozilla #endif /* MOZILLA_GFX_TYPES_H_ */