mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
8637eba4b3
- remove poisondata stuff (cf5b5d29e5) - Bug 1218488 - clarify buffer ownership for nsICanvasRenderingContextInternal::GetBuffer; r=Bas,baku (dba4272b73) - Bug 1167215 - Re-apply CompositeUntil calls when we get a new batch of textures. r=roc (d57a8ac9e9) - Bug 1220923 - Make nsIntRegion a typedef for IntRegionTyped<UnknownUnits>. r=nical (a5f4e1e283) - Bug 1220898 - Make nsIntMargin a typedef for mozilla::gfx::IntMargin. r=nical (8bdb2f191a) - Bug 1205913 - Differentiate YCbCr, NV12 and RGB textures when drawing layer borders. r=nical (ff5d3dc7df) - Bug 1203376 - Honor filter region settings for lighting filters. r=mstange (8d0565e99a) - Bug 1220512 - ensure next frame status is updated before notifying MediaDecoder::PlaybackEnded. See bug 1220512 comment 1 for the detail. r=cpearce. (c2f434b5d4) - Bug 1207964 - Remove workaround from bug 1080461. r=jwwang (19bff98c14) - Bug 1199904: Only start decoding ahead after explicitly requesting data. r=gerald (8712637b49) - Bug 1197664: Report the total number of decoded frames. CLOSED TREE r=kentuckyfriedtakahe (422827d1af) - Bug 1178596: Reset frame size queue after flushing. r=cpearce (dd40ac4e6b) - Bug 1205911: P1. Cancel pending demux request when searching for next keyframe. r=edwin (8a03e6904f) - Bug 1188313: P1. Attempt to seek audio near video. r=cpearce (a8b6465d97) - Bug 1205911: P2. Ensure demuxer is reset before performing a seek. r=edwin (e93534a1d1) - bit of Bug 1185886: P2 (c2e89be4a3) - bit of Bug 1211443 (98fbb4a4a2) - Bug 1089586: Abort pending seeks. r=jwwang (e81f453204) - Bug 1195094: P1. Properly detects SPS changes for decoders requiring Annex B. r=cpearce (976febcd7c) - Bug 1195094: P2. Ensure TrackInfo object passed to constructor is never modified. r=cpearce (d5c15b2368) - Bug 1218577: Use only Blank PDM if enabled. r=kamidphish (a7e06549cc) - Bug 1210231 - Enable unencrypted <video> playback using Adobe's GMP for decoding. r=jya (7f80702b89) - Bug 1214932 - Add media.wmf.enabled pref. r=jya (8c183c0dd1) - Bug 1213173: Always use FFmpeg regardless of version. r=kentuckyfriedtakahe (e5af2c0c91) - Bug 1211787 - Improve the accuracy of MediaDecoderStateMachine::GetDecodedAudioDuration(). r=roc. (16d755c555) - Bug 1193614 - Schedule State Machine when VideoQueue() is low. r=cpearce (fe608da5fd) - Bug 1219984. Part 1 - remove EventPassMode::Both. In order to support multiple arguments, all arguments must be either moved or copied. r=kinetik. (2ee049008c) - Bug 1219984. Part 2 - add support for multiple arguments. r=kinetik. (1c70d5d69b) - Bug 1219974 - Add DisconnectIfExists() to MediaEventListener. r=kinetik. (43f6ae90b0) - Bug 1192109 - Fix insufficient includes in MediaEventSource.h. r=kinetik. (09eca240a1) - mData, aData (5e87f70853) - Bug 1219330 - Handle PlanaYCbCrImage::SetData failure. r=jya, jesup (144f3c266f) - Bug 1222308. Assume frames that are very old will never be composited. r=nical (1da9be2527) - space (45b67caa85) - Bug 1182426 - Set PlanarYCbCrImage's size in VP8TrackEncoder GTest. r=roc (d70a4d20c4) - Bug 1217080. Move recycling functionality into RecyclingPlanarYCbCrImage. r=nical (e2b2f650d7) - Bug 1216644 - part 1 - simple s/nsAutoArrayPtr/UniquePtr/ changes in gfx/; r=jrmuizel (d19bc51f94) - Bug 1216644 - part 2 - make gfxFontEntry::mUVSData a UniquePtr; r=jrmuizel (605a1bc6b1) - Bug 1216644 - part 3 - make BufferRecycleBin store UniquePtrs; r=jrmuizel (7781281266) - Add an RAII class to lock and unlock textures. (bug 1222863 part 1, r=nical) (abdec485f3) - Use RAII for more TextureClient locking cases. (bug 1222863 part 2, r=nical) (b35486ed3d) - Bug 1212288 - Make ImageContainer::AllocateProducerID callable on all threads; r=roc (fc569b8e48) - Bug 1140947 - Correct some logging in SourceBufferResource.cpp. r=cajbir (fcbb38056c) - Bug 1199573: [MSE] Properly handle partial media header received prior a discontinuity. r=gerald (f1cda54fa3) - Bug 1213726 - Remove AbstractMediaDecoder::HasInitializationData(). r=kinetik. (62f09f816e) - Bug 1034081 - Never seek before startTime. r=rillian Only adjust seek target up to startTime (44139b20ec) - Bug 1196353 - Use standard Xiph extradata format to pass headers from demuxers to decoders. r=jya (41f8dee5af) - Bug 1202332 - XiphExtradataToHeaders miscalculates final header length. r=derf (eec20f90f0) - Bug 1208799: [webm] Use first track found. r=kinetik (7196355e31) - Bug 1190472 - part 1 - improve MediaRawDataQueue's reference-counting behavior; r=kinetik (47b066b8e8) - Bug 1190472 - part 2 - delete unused MediaRawDataQueue::Push method; r=kinetik (f8246efe1b) - Bug 1190472 - part 3 - optimize pushing an entire queue onto MediaRawDataQueue; r=kinetik (045b389bf8) - Bug 1213024 - Comment the structured clone reading and writing, r=fitzgen (1b64f9f502) - Bug 1201620 - Make SavedFrame stacks structured cloneable; r=sfink (87e9b0a04b) - Bug 1221456 - Avoid C4819 warning spam. r=glandium (3dde3cb10a) - Bug 1213752 - IonMonkey: MIPS: Enable MIPS64 support. r=glandium (36da4cbd99) - Bug 1214175 - Make hash table manipulation infallible in Shape::fixupGetterSetterForBarrier() r=terrence (98e5e601ec) - Bug 1215337 - Cache slotSpan(), r=terrence (3e992f9f06) - No Bug - Include jswin.h in jsobj.cpp to unbreak windows non-unified bustage. (r=terrence over IRC) (92cba3254f) - Bug 1052139 - Make prototype-setting first create Object.prototype so that subsequent prototype chain-splicing will work correctly. r=bz (34a8d00d9f) - Bug 1172076 - Improve js::DumpBacktrace to include raw frame pointers and types. r=jandem (f11eb1763b) - Bug 1052139 - Change the boolean constant controlling whether the global object prototype chain is immutable, to enable immutable-prototype enforcement generally. r=duh (b7a1124feb) - Bug 1215363 - Fix a couple of OOM handling issues and make JS_sprintf funcions crash when passed illegal format strings r=terrence (c778891dd3) - Bug 1211331 - Ensure that GC slices are terminated such that we can safely iterate the heap. r=terrence (440308a333) - Bug 1224048 - Use stable hashing for the temporary tables in the JSON parser; r=jonco (7d058f44c9) - Bug 1215678 - Nuke cross compartment wrappers if we fail to add them to the wrapper map r=terrence (8e9e535a11) - Bug 1200732 - Use stable hashing for AutoCycleDetectorSet; r=jonco (68237bdea4) - more poisondata removal (6479b20220) - Bug 1218488 - clarify buffer ownership for nsICanvasRenderingContextInternal::GetBuffer; r=Bas,baku (ae89d929b2) - Bug 1207378 (Part 1) - Add support for a frame rect to Downscaler. r=tn (234866c32f) - Bug 1207378 (Part 2) - Use Downscaler to remove first-frame padding when downscaling GIFs. r=tn (5e995bdca2) - Bug 1207378 - Add FrameRect to non-skia version of BeginFrame. r=seth (939f0510eb) - Bug 1204394 (part 1) - Using StreamingLexer in the BMP decoder. r=seth. (77eaa1e125) - Bug 1204394 (part 2) - Add bmpsuite to the BMP reftests. r=seth. (237a902461) - Bug 1214476 - Remove unused code for encoding BMPv2 files. r=seth. (b8382357d7) - Bug 1213613 (part 1) - Formatting cleanups for nsBMPEncoder.h. r=seth. (4ee65bc173) - Bug 1213613 (part 2) - Move some BMP-related structs. r=seth. (15289784ce) - Bug 1215156 - move SetPixel* functions into nsBMPDecoder.cpp; r=seth (a143c843d4) - Bug 1215763 - part 1 - remove unnecessary nsAutoPtr.h includes; r=seth (f8a3a1f6b0) - Bug 1180715 (1/4) - Track image LoadTime to compare with file mtime. review=seth (bdbd25752c) - Bug 1180715 (2/4) - Provide a nsIFileURL interface for thumbnails. review=ttaubert (24c506569d) - Bug 1147562 - Update remaining callsites of newChannel before landing the shim in toolkit/ (r=gijs) (f7f2ab798f) - Bug 1163866 - Set originalURI correctly for moz-page-thumb:// channels. r=adw (3c7c97928e) - Bug 1180715 (3/4) - Drop parseURI from newChannel2. review=ttaubert (5b409e7d4b) - Bug 1180715 (4/4) - Use nsIURL methods instead of RegExp. review=ttaubert (1f7a026e06) - Bug 1209705 - Propagate the DrawResult for temporary surfaces to the caller in ClippedImage. r=tn (c5be1c7df4) - Bug 1215763 - part 2 - s/nsAutoPtr/UniquePtr/ in image/; r=seth (58c5da3bd2) - Bug 1215763 - part 3 - s/nsAutoArrayPtr/UniquePtr/ in nsBMPEncoder; r=seth (62bc939286) - Bug 1213613 (part 3) - Fix color-scaling of 16bpp BMP images. r=seth. (d06d511564) - Bug 1214072 (part 1) - Read BMP bitfields during metadata decoding. r=seth. (56cc2c02cd) - Bug 1214072 (part 2) - Implement transparency properly for BMP images. r=seth. (b6b07c2d90) - Bug 1218823 - use UniquePtr<> in preference to delete[] in image/; r=seth (5cd21f89a2) - Bug 1215334 (part 1) - Avoid creating a fake header for BMP files in ICO files. r=seth. (67506fc53e) - Bug 1215334 (part 2) - Avoid creating a fake header for BMP files in ICO files. r=seth. (cf6c3f4553) - spacing (b91c58ec87) - Bug 1196494 - part 1: remove unnecessary GetClientBounds call in CompositorParent. r=jrmuziel (685f49ae9c) - Bug 1180008 - Define gtk_window_get_window_type in mozgtk. r=karlt (e7ca7db4d3) - Bug 863512 - Fixing xul dnd panels for linux. r=enndeakin (5d0faaf0dc) - Bug 1195002 - draw to MozContainer window to allow GTK to draw decorations, r=karlt (7a84272fe9) - Bug 1210249 - don't mess with toplevel widget when client side decorations are enabled. r=karlt (464e9ce3fb) - bug 1180008 use mGdkWindow instead of finding it from gtk_widget_get_window(mShell) r=acomminos (024f8bd5a7) - bug 1180008 don't measure size of decorations for override-redirect windows r=acomminos (416ffda363) - Bug 1026803 part 1 - Factor out a common utility class for converting wrapping native times to TimeStamps; r=karlt (915ecdfc40) - Bug 1026803 part 2 - Add an assertion that SystemTimeConverter's template parameter is unsigned; r=karlt (68ccf1569d) - Bug 1026803 part 3 - Make some simplifications to SystemTimeConverter; r=karlt (c38719b7de) - Bug 1026803 part 4 - Convert GTK native event times to timestamps; r=karlt (74ef903992) - Bug 1026803 part 5 - Convert CurrentXXXTimeGetter classes from functors to helper classes; r=karlt (06d49e5965) - Bug 1026803 part 6 - Make SystemTimeConverter detect clock skew; r=karlt (d663ab72b2) - Bug 1026803 part 7 - Store the CurrentX11TimeGetter as a member object on nsWindow; r=karlt (f6a04e6e9c) - Bug 1026803 part 8 - Add ability for CurrentX11TimeGetter to perform an asynchronous request of the current time; r=karlt (961dab1d91) - Bug 1026803 part 8b - Factor out an IsTimeNewerThanTimeStamp method; r=karlt (1afb9f511a) - Bug 1026803 part 9 - Return DOMHighResTimeStamp objects from Event.timeStamp on Linux for Nightly/Aurora builds; r=karlt (975432dbd8) - Fix bustage from changeset 5c5dc6f367ac (bug 1026803) r=bustage on CLOSED TREE (c0be358f84) - fix bustage (e5e97018b6) - Bug 1196494 - part 2: only update nsWindow client offset when _NET_FRAME_EXTENTS property actually changes. r=eihrul (dd7e913d49) - Bug 1170342 - Disable XInput2 by default on GTK3. r=karlt (6a52d65a98) - Bug 1208904 - Fix a condition in nsWindow::SetNonClientMargins; r=roc (fe8c7b3e77) - Bug 1199892 - "Mouse cursor flickers in Flash object with wmode opaque/transparent". r=roc (6d50037e14) - Bug 1171101 - Remove pointer events and gesture scrolling dependencies. r=smaug (3aa5c89ea4) - Bug 978679. Implement touch events for GTK3. r=karlt (adafe58640) - Bug 1209774 - Transform from GDK coords to layout device pixels before calling DispatchEvent. r=karlt (4c81cf74ea) - Bug 1191293. Remove harmless assertion that is triggered by GTK3. r=masayuki (e0b9eb2c80) - Bug 978679. Convert GDK touch event coordinates properly. r=karlt (dfeae08f47) - restore some XP vs Vista differences, Bug 925599 bits (88ff57f06f) - Bug 1220392 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in widget/; r=roc (35026aa4c9) - Bug 1214616 - Remove encoding conversion methods from nsPrimitiveHelpers. r=emk. (3a4bdbbc8e) - Bug 1216611 - add mozilla::MakeUniqueFallible and convert uses throughout the tree; r=Waldo (8672c2e3d9) - Bug 1216964 - remove nsAutoArrayPtr use from ActorsParent; r=khuey (ddff59241a) - Bug 1219903 - use UniquePtr<T[]> instead of delete[] calls in layout/generic/; r=dholbert (8b96067a6e) - Bug 1220190 - use UniquePtr<T[]> instead of delete[] calls in layout/xul/; r=dholbert (065b3c521c) - Bug 1220714 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in layout/; r=dholbert (6a8245751c) - Bug 1221550 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in intl/; r=smontagu (67868889e2) - Bug 1232374 - remove nsAutoArrayPtr usages from toolkit/; r=froydnj (d65586df26) - Bug 1170522 - expose whether or not we're in tablet mode to xul/js/css, r=jimm,ted (5cb134a8d4) - bug 1163872 - Fix a unified build issue in nsXPLookAndFeel.cpp. r=jimm (925e38abed) - bug 1217602 - remove nsIPKIParamBlock r=Cykesiopka (b5f0fc8dfd) - missing bit of old bug (fdcb4fe143) - Bug 1221453 - Use ObjDirPaths for GENERATED_INCLUDES and merge with LOCAL_INCLUDES. r=gps (a0537fff83) - Bug 1194948 - Build gfx/ipc in unified mode and mark as FAIL_ON_WARNINGS. r=BenWa (c88b356ac8) - Bug 815952 - Stop clearing clipboard data originating from a private window after closing private windows. r=ehsan (b94fea061d) - Bug 943296 - widget/gtk/nsDragService.cpp should assume Gtk uses UTF-8. r=karlt. (3613e87354) - Bug 1186661 - Draw drag and drop alpha pixmap correctly on GTK3. r=karlt (ca884af03b) - Bug 983843 - Switch to GtkOffscreenWindow for drag source widget, fixing ghost tabs on some GTK versions. r=karlt (ab56f9d764) - bug 1216916 clean up when InvokeDragSession() fails r=roc (30c811c33e) - Bug 1198128 - Fix -Wshadow warnings in widget/gtk. r=karlt (06bc60349e) - Merge branch 'dev' of https://github.com/rmottola/Arctic-Fox into dev (c79378b7c9) - Bug 1206915 - Move dumping of compositor textures under its own environment variable. r=mattwoodrow (b8ba4f0fbf) - Bug 1213007 - Part 1. Implementing gfxCrash. r=dvander (e307f9d543) - Bug 1208661 - Show display list and layer textures in-line in the HTML paint dump. r=BenWa (7047c68964) - Relax the driver crash guard on nightly and e10s builds. (bug 1200825, r=jgilbert) (1dd81b1257) - Bug 1214802 - gfxEnv - consolidate environment variables used by the graphics code in one place. r=botond (afb61356c6) - Bug 1217192 - Use gfxCriticalNote where we're already using the non-default construction parameter. r=mchang (d04ca17de5) - addback some crash stuff (8a78973a71) - Fix layers.acceleration.force-enabled not working. (bug 1212659, r=jrmuizel) (5eb85d8f64) - Bug 1142516 - Improve assertions and logging on the compositor side. r=Bas (cca63735e5) - Bug 1194335. Use a StackArray for RECTS so we see them in the minidumps. r=mattwoodrow (1a83a134e8) - Bug 1192058 - For DXGI_PRESENT_PARAMETERS, set pDirtyRects to nullptr if DirtyRectsCount == 0. r=BenWa (f78ff0df24) - Bug 1204922 - More information about crashes. r=bas (53cbd02c12) - Bug 1222033 - Rename gfxCrash to gfxDevCrash. r=jrmuizel (32351d0bc7) - Bug 1209812 (part 1) - Remove casts between cairo_format_t and gfxImageFormat. r=nical. (c1bc5cd74c) - Bug 1209812 (part 2) - Remove gfxImageFormat::A1. r=nical. (99f665ad80) - Bug 1182426 - Sort includes in VP8TrackEncoder.cpp alphabetically. r=roc (5f10334ba8) - Bug 1182426 - Don't try to encode new frames of a size other than the initial in VP8TrackEncoder. r=roc (8fb0b8f0d9) - Bug 1182426 - Flatten YUV formats conversion code in VP8TrackEncoder. r=roc (0853d098f7) - Bug 1182426 - Convert non-PlanarYCbCRImages in VP8TrackEncoder. r=roc (d2d78fa94a) - Bug 1204106 - Use correct alpha blend modes for OVER in CompositorOGL. r=jrmuizel (5cc211b9d6) - Bug 1207326 - Part 1: Correct projection clipping rectangle,r=matt.woodrow (8329afb6a7) - Bug 1207326 - Part 2: Add reftest,r=jmuizelaar (d17d6c5d4f) - Bug 1209446 - Make sure mFrameInProgress flag is set to true only when we actually begin drawing new frame. r=nical (4ff48c4149) - Disable screen and multiply mix-blend-mode support in the D3D11 and OGL compositors. (bug 1135271, r=mattwoodrow) (9b4c11a289) - Bug 1210189 - Use nsScreenGonk in nsWindow::StartRemoteDrawing() r=mwu (2653a33972) - Bug 1210514 - Fix color inversion when BasicCompositor is used on gonk r=nical (141fee3bfb) - Bug 1209812 (part 3) - Rename SurfaceFormat::R5G6B5 as R5G6B5_UINT16. r=Bas. (915e7eaba3) - Bug 1209812 (part 4) - Add comments to SurfaceFormat. r=jrmuizel,Bas. (ef1977582f) - Bug 1209812 (part 5) - Add endian-neutral variants to SurfaceFormat. r=nical,Bas. (93c49df8c5) - Bug 1171671 - Simplify Boot Animation control r=mwu (94c4f89b45) - Bug 1210182 - Implement GrallocTextureHostBasic r=nical (4e5ea5b92c) - Bug 1209812 (follow-up) - Android bustage fix on a CLOSED TREE. r=me. (8b2fa6268d) - Bug 1178513 - Added RGBA8888 to RGB565 converter. r=mattwoodrow (8ba5dbd3c9) - Bug 1160689 - thumbnail image corruption on certain videos. r=sotaro (278a2e29f6) - Bug 1204922: When ResizeBuffers fails, make no attempt to do subsequent paints until it succeeds again. r=milan (0c040d8228) - Bug 1215027 - Fix EndFrameForExternalComposition() r=nical (bab4690e54) - Bug 1215364 - Implement BasicCOmpositor::EndFrameForExternalComposition r=nical (c8b9c7bfb9) - Bug 1213968 - Renew the surface on iOS when resuming the compositor r=kats (73489dc21c) - Bug 1201318 - Factor out AddFamily. r=jdaggett (3f2556b8b4) - Bug 1201318 - revise OSX system font handling. r=mstange (f8a8f5f562) - Bug 1163877 - Part 1: Add storage for other FontFaceSets a FontFace is in. r=jdaggett (ab3a16b597) - Bug 1163877 - Part 2: Allow FontFaces to be added to multiple FontFaceSets. r=jdaggett (9b2dd7e5c9) - Bug 1163877 - Part 3: Update state on, and reflow documents for, all FontFaceSets that contain a FontFace whose user font entry updated. r=jdaggett (215db30569) - Bug 1192986 Fix test_interfaces.html to expect Cache API and font loading to be released. r=ehsan (8db9ef1df8) - Bug 1193019 - Rename CSSFontFaceLoadEvent to FontFaceSetLoadEvent. r=khuey (53f373c53d) - Bug 1163877 - Part 4: Tests. r=jdaggett (c6053ca8b4) - Bug 1180415 - initialize downloadable font pattern from FTFace. r=karlt (04aa59ba79) - Bug 1163491 - map local fontnames to fontconfig patterns. r=karlt (ad10ebde2a) - Bug 543715 p1 - distinguish between italic and oblique. r=jfkthame (4c9a0abf64) - Bug 543715 p2 - italic/oblique reftests. r=jfkthame (90fb927148) - bug 1178733 - enable APZ for iOS. r=kats (e41702d9cd) - Bug 1169956. Backout bug 1073209 for tiled image regressions on OS X. r=jrmuizel (a80a29aaa3) - Bug 1073209 - Eliminate usage of CreateSamplingRestrictedDrawable on d2d backends. r=jrmuizel (9ac8781a52) - Bug 1204136 - Align DisplayPort on non-tiling platform. r=botond (1d8be17663) - Bug 1122918 - Put the logical values for 'float' and 'clear' behind a pref, and enable them only on nightly builds and for B2G. r=heycam (a428b34d66) - Bug 1183484 - Cycle collect FontFaceSetIterator. r=bzbarsky (dc49f3f098) - Bug 1027579 - Do not load fonts from the cache if LOAD_BYPASS_CACHE is set. r=jfkthame r=bz (6cf20c9119) - Bug 1201318 - Use nsAutoReleasePool from nsCocoaUtils.h. r=jdaggett (bfe5f05086) - Bug 1201403 - streamline MacOSFontEntry::HasFontTable implementation. r=jfkthame (da06064b86) - Bug 1165611 - fix font smoothing under Linux. r=karlt (166a96603b) - Bug 1160506 - support intra-family font fallback. r=heycam (f56f0507d0) - Bug 1165693 - Cache the result of calling FcConfigSubstitute for our sentinel font name, to make gfxFcPlatformFontList::FindFamily less expensive. r=jdaggett (09ace74bc1) - Bug 1165693 - patch 2 - Cache family-name lookups in gfxFcPlatformFontList::FindFamily, to avoid repeating expensive calls to FcConfigSubstitute. r=jdaggett (ab34bf45c0) - Bug 1174946 - Back out the (incorrectly-implemented) caching of sentinelFirstFamily from bug 1165693, which should be largely overshadowed by the mFcSubstituteCache anyway. r=jdaggett (9b7784b7a6) - Bug 1165766 - Crash in AddFontSetFamilies() r=jtd (13cba8e6c7) - Bug 1170421 - return first font suggested by fontconfig as the default font. r=karlt (426c6bd348) - Bug 1008169 - Font selection and font size dropdowns are reacting very slowly on press up/down,r=jaws (8e395026e1) - Bug 1166161 - Display available font from font.name-list.{family}.{lang} as fallback default font, instead of empty string. (045855761a) - Bug 1187680 - Use NSVisualEffectMaterialMenu for menus if it's available. r=smichaud (0cede2f295) - Bug 1190257. Use the previous vsync timestamp on windows 10. r=jrmuizel (7cf7e2644f) - Bug 1220699 - Add telemetry probe to measure vsync latency in the parent refresh driver. r=avih (347936dffb) - Bug 1221674 - Add telemetry probe in the content process to measure the time between refresh driver ticks. r=kats (1d1b885f10) - Bug 1198362 - Delete PreciseRefreshDriverTimer. r=roc (8fdcca758f) - Bug 1197898 - Delete vsync refresh driver preference. r=kats (eab85ba8dd) - Bug 1210250. Fallback to GDI fonts with a skia backend. r=jwatt (8c374b4bd3) - Bug 1208927 - Initialize queryD3DKMTStatistics so that it can't be accessed uninitialized; r=jrmuizel (69c6781a82) - Bug 1144946 - Delete PreciseRefreshDriverTimerWindowsDwmVsync refresh driver timer. r=roc (a78ccb3d42) - Bug 1187784 (part 4) - Replace nsBaseHashtable::EnumerateRead() calls in layout/ with iterators. r=heycam. (6a09016e6d) - Bug 1187784 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in layout/ with iterators. r=heycam. (1ce8abd863) - Bug 1187784 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in layout/ with iterators. r=heycam. (cd98be2f19) - Bug 1187784 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in layout/ with iterators. r=heycam. (09022514a9) - Bug 1217230 - Set mNeedToRecomputeVisibility true only when style or layout flush. r=seth (8f3edd57c0) - Bug 1167281 - sort scalable fonts first when resolving generic families under Linux. r=karlt (e2ecb89f31) - Bug 1186875 - check if FcFontSort returns non-null. r=jtd (087905da51) - Bug 1218617 - Invalidate whole widget area after external composition r=mattwoodrow (3901f416f5) - Bug 1153499 - Enable push and sw prefs. r=dougt,ehsan (ca0f3a105d) - Bug 1141415 - add expire setting of permission to SpecialPowers. r=jmaher (372bc0c930) - partial Bug 1196665 - Add originAttributes into SpecialPowers. r=bholley (b8407a1bcc) - Bug 1213151 - Part 1: Add a SpecialPowers API for cleaning up the STS data that works in both e10s and non-e10s modes; r=jdm (04bba17fd3) - Bug 1213151 - Part 2: Use SpecialPowers.cleanUpSTSData() in a few tests; r=jdm (cce5f23dac) - Bug 1214593 - Remove service worker periodic updater. r=ehsan (87cfebcd0d) - fix tests, fix spaces (9cba57e7ff) - Bug 1207499 - Part 10: Remove use of expression closure from testing/. r=jmaher (652faa8963) - Bug 1204154 - Clean up jar manifests that needlessly specify the source file. r=dao (f116e33bed) - Bug 1222943 (part 1) - Change Touch::mRadius from nsIntPoint to LayoutDeviceIntPoint. r=kats. (dcc6c15797) - Bug 1222943 (part 2) - Remove an unnecessary call to ToUnknownSize(). r=botond. (08f644f194) - Bug 1220925 - Event::GetScreenCoords should return CSSIntPoint instead of LayoutDevicePoint. r=botond (4e4f54e8e7) - Bug 943294 - Leave dealing with legacy codepages for clipboard data to Windows itself. r=jmathies. (124ecbfa3e) - Bug 1243507 - Reimplement non-Unicode clipboard formats as bug 943294 broke drag and drop between some Unicode-unaware apps. r=jimm (02edc31ed9) - ported Bug 1254980 - Ensure that text/html is still written to the clipboard. r=enndeakin a=sylvestre (9cd4c0e41a) - nsWindow: build fix (1c3e798a89)
1608 lines
51 KiB
C++
1608 lines
51 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* 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/. */
|
|
|
|
#include <initguid.h>
|
|
#include "DrawTargetD2D1.h"
|
|
#include "DrawTargetD2D.h"
|
|
#include "FilterNodeSoftware.h"
|
|
#include "GradientStopsD2D.h"
|
|
#include "SourceSurfaceD2D1.h"
|
|
#include "SourceSurfaceD2D.h"
|
|
#include "RadialGradientEffectD2D1.h"
|
|
|
|
#include "HelpersD2D.h"
|
|
#include "FilterNodeD2D1.h"
|
|
#include "Tools.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
|
|
uint64_t DrawTargetD2D1::mVRAMUsageDT;
|
|
uint64_t DrawTargetD2D1::mVRAMUsageSS;
|
|
ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr;
|
|
|
|
ID2D1Factory1 *D2DFactory1()
|
|
{
|
|
return DrawTargetD2D1::factory();
|
|
}
|
|
|
|
DrawTargetD2D1::DrawTargetD2D1()
|
|
: mClipsArePushed(false)
|
|
{
|
|
}
|
|
|
|
DrawTargetD2D1::~DrawTargetD2D1()
|
|
{
|
|
PopAllClips();
|
|
|
|
if (mSnapshot) {
|
|
// We may hold the only reference. MarkIndependent will clear mSnapshot;
|
|
// keep the snapshot object alive so it doesn't get destroyed while
|
|
// MarkIndependent is running.
|
|
RefPtr<SourceSurfaceD2D1> deathGrip = mSnapshot;
|
|
// mSnapshot can be treated as independent of this DrawTarget since we know
|
|
// this DrawTarget won't change again.
|
|
deathGrip->MarkIndependent();
|
|
// mSnapshot will be cleared now.
|
|
}
|
|
|
|
if (mDC) {
|
|
// The only way mDC can be null is if Init failed, but it can happen and the
|
|
// destructor is the only place where we need to check for it since the
|
|
// DrawTarget will destroyed right after Init fails.
|
|
mDC->EndDraw();
|
|
}
|
|
|
|
// Targets depending on us can break that dependency, since we're obviously not going to
|
|
// be modified in the future.
|
|
for (auto iter = mDependentTargets.begin();
|
|
iter != mDependentTargets.end(); iter++) {
|
|
(*iter)->mDependingOnTargets.erase(this);
|
|
}
|
|
// Our dependencies on other targets no longer matter.
|
|
for (TargetSet::iterator iter = mDependingOnTargets.begin();
|
|
iter != mDependingOnTargets.end(); iter++) {
|
|
(*iter)->mDependentTargets.erase(this);
|
|
}
|
|
}
|
|
|
|
already_AddRefed<SourceSurface>
|
|
DrawTargetD2D1::Snapshot()
|
|
{
|
|
if (mSnapshot) {
|
|
RefPtr<SourceSurface> snapshot(mSnapshot);
|
|
return snapshot.forget();
|
|
}
|
|
PopAllClips();
|
|
|
|
mDC->Flush();
|
|
|
|
mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this);
|
|
|
|
RefPtr<SourceSurface> snapshot(mSnapshot);
|
|
return snapshot.forget();
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::Flush()
|
|
{
|
|
mDC->Flush();
|
|
|
|
// We no longer depend on any target.
|
|
for (TargetSet::iterator iter = mDependingOnTargets.begin();
|
|
iter != mDependingOnTargets.end(); iter++) {
|
|
(*iter)->mDependentTargets.erase(this);
|
|
}
|
|
mDependingOnTargets.clear();
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
|
|
const Rect &aDest,
|
|
const Rect &aSource,
|
|
const DrawSurfaceOptions &aSurfOptions,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
|
|
|
|
D2D1_RECT_F samplingBounds;
|
|
|
|
if (aSurfOptions.mSamplingBounds == SamplingBounds::BOUNDED) {
|
|
samplingBounds = D2DRect(aSource);
|
|
} else {
|
|
samplingBounds = D2D1::RectF(0, 0, Float(aSurface->GetSize().width), Float(aSurface->GetSize().height));
|
|
}
|
|
|
|
Float xScale = aDest.width / aSource.width;
|
|
Float yScale = aDest.height / aSource.height;
|
|
|
|
RefPtr<ID2D1ImageBrush> brush;
|
|
|
|
// Here we scale the source pattern up to the size and position where we want
|
|
// it to be.
|
|
Matrix transform;
|
|
transform.PreTranslate(aDest.x - aSource.x * xScale, aDest.y - aSource.y * yScale);
|
|
transform.PreScale(xScale, yScale);
|
|
|
|
RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, transform, ExtendMode::CLAMP);
|
|
|
|
if (!image) {
|
|
gfxWarning() << *this << ": Unable to get D2D image for surface.";
|
|
return;
|
|
}
|
|
|
|
RefPtr<ID2D1Bitmap> bitmap;
|
|
if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
|
|
// If this is called with a DataSourceSurface it might do a partial upload
|
|
// that our DrawBitmap call doesn't support.
|
|
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
|
|
}
|
|
|
|
if (bitmap && aSurfOptions.mSamplingBounds == SamplingBounds::UNBOUNDED) {
|
|
mDC->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(aSource));
|
|
} else {
|
|
// This has issues ignoring the alpha channel on windows 7 with images marked opaque.
|
|
MOZ_ASSERT(aSurface->GetFormat() != SurfaceFormat::B8G8R8X8);
|
|
mDC->CreateImageBrush(image,
|
|
D2D1::ImageBrushProperties(samplingBounds,
|
|
D2D1_EXTEND_MODE_CLAMP,
|
|
D2D1_EXTEND_MODE_CLAMP,
|
|
D2DInterpolationMode(aSurfOptions.mFilter)),
|
|
D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
|
|
getter_AddRefs(brush));
|
|
mDC->FillRectangle(D2DRect(aDest), brush);
|
|
}
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::DrawFilter(FilterNode *aNode,
|
|
const Rect &aSourceRect,
|
|
const Point &aDestPoint,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
if (aNode->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
|
|
gfxWarning() << *this << ": Incompatible filter passed to DrawFilter.";
|
|
return;
|
|
}
|
|
|
|
PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
FilterNodeD2D1* node = static_cast<FilterNodeD2D1*>(aNode);
|
|
node->WillDraw(this);
|
|
|
|
mDC->DrawImage(node->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
|
|
const Point &aDest,
|
|
const Color &aColor,
|
|
const Point &aOffset,
|
|
Float aSigma,
|
|
CompositionOp aOperator)
|
|
{
|
|
MarkChanged();
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
Matrix mat;
|
|
RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
|
|
|
|
if (!image) {
|
|
gfxWarning() << "Couldn't get image for surface.";
|
|
return;
|
|
}
|
|
|
|
if (!mat.IsIdentity()) {
|
|
gfxDebug() << *this << ": At this point complex partial uploads are not supported for Shadow surfaces.";
|
|
return;
|
|
}
|
|
|
|
// Step 1, create the shadow effect.
|
|
RefPtr<ID2D1Effect> shadowEffect;
|
|
HRESULT hr = mDC->CreateEffect(CLSID_D2D1Shadow, getter_AddRefs(shadowEffect));
|
|
if (FAILED(hr) || !shadowEffect) {
|
|
gfxWarning() << "Failed to create shadow effect. Code: " << hexa(hr);
|
|
return;
|
|
}
|
|
shadowEffect->SetInput(0, image);
|
|
shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
|
|
D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a };
|
|
shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
|
|
|
|
D2D1_POINT_2F shadowPoint = D2DPoint(aDest + aOffset);
|
|
mDC->DrawImage(shadowEffect, &shadowPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
|
|
|
|
D2D1_POINT_2F imgPoint = D2DPoint(aDest);
|
|
mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::ClearRect(const Rect &aRect)
|
|
{
|
|
MarkChanged();
|
|
|
|
PopAllClips();
|
|
|
|
PushClipRect(aRect);
|
|
|
|
if (mTransformDirty ||
|
|
!mTransform.IsIdentity()) {
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
D2D1_RECT_F clipRect;
|
|
bool isPixelAligned;
|
|
if (mTransform.IsRectilinear() &&
|
|
GetDeviceSpaceClipRect(clipRect, isPixelAligned)) {
|
|
mDC->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
mDC->Clear();
|
|
mDC->PopAxisAlignedClip();
|
|
|
|
PopClip();
|
|
return;
|
|
}
|
|
|
|
mDC->SetTarget(mTempBitmap);
|
|
mDC->Clear();
|
|
|
|
IntRect addClipRect;
|
|
RefPtr<ID2D1Geometry> geom = GetClippedGeometry(&addClipRect);
|
|
|
|
RefPtr<ID2D1SolidColorBrush> brush;
|
|
mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), getter_AddRefs(brush));
|
|
mDC->PushAxisAlignedClip(D2D1::RectF(addClipRect.x, addClipRect.y, addClipRect.XMost(), addClipRect.YMost()), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
mDC->FillGeometry(geom, brush);
|
|
mDC->PopAxisAlignedClip();
|
|
|
|
mDC->SetTarget(mBitmap);
|
|
mDC->DrawImage(mTempBitmap, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
|
|
|
|
PopClip();
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::MaskSurface(const Pattern &aSource,
|
|
SourceSurface *aMask,
|
|
Point aOffset,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
MarkChanged();
|
|
|
|
RefPtr<ID2D1Bitmap> bitmap;
|
|
|
|
RefPtr<ID2D1Image> image = GetImageForSurface(aMask, ExtendMode::CLAMP);
|
|
|
|
if (!image) {
|
|
gfxWarning() << "Failed to get image for surface.";
|
|
return;
|
|
}
|
|
|
|
PrepareForDrawing(aOptions.mCompositionOp, aSource);
|
|
|
|
// FillOpacityMask only works if the antialias mode is MODE_ALIASED
|
|
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
|
IntSize size = aMask->GetSize();
|
|
Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
|
|
image->QueryInterface((ID2D1Bitmap**)&bitmap);
|
|
if (!bitmap) {
|
|
gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
|
|
return;
|
|
}
|
|
|
|
Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
|
|
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
|
|
|
|
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aSource);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
|
|
const IntRect &aSourceRect,
|
|
const IntPoint &aDestination)
|
|
{
|
|
MarkChanged();
|
|
|
|
PopAllClips();
|
|
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
Matrix mat;
|
|
RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
|
|
|
|
if (!image) {
|
|
gfxWarning() << "Couldn't get image for surface.";
|
|
return;
|
|
}
|
|
|
|
if (!mat.IsIdentity()) {
|
|
gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface.";
|
|
return;
|
|
}
|
|
|
|
RefPtr<ID2D1Bitmap> bitmap;
|
|
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
|
|
|
|
if (bitmap && mFormat == SurfaceFormat::A8) {
|
|
RefPtr<ID2D1SolidColorBrush> brush;
|
|
mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
|
|
D2D1::BrushProperties(), getter_AddRefs(brush));
|
|
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
|
|
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
|
|
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
|
|
return;
|
|
}
|
|
|
|
Rect srcRect(Float(aSourceRect.x), Float(aSourceRect.y),
|
|
Float(aSourceRect.width), Float(aSourceRect.height));
|
|
|
|
Rect dstRect(Float(aDestination.x), Float(aDestination.y),
|
|
Float(aSourceRect.width), Float(aSourceRect.height));
|
|
|
|
if (bitmap) {
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
|
|
mDC->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f,
|
|
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
|
|
D2DRect(srcRect));
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
|
|
return;
|
|
}
|
|
|
|
mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)),
|
|
D2DRect(srcRect), D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
|
|
D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::FillRect(const Rect &aRect,
|
|
const Pattern &aPattern,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
mDC->FillRectangle(D2DRect(aRect), brush);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::StrokeRect(const Rect &aRect,
|
|
const Pattern &aPattern,
|
|
const StrokeOptions &aStrokeOptions,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
|
|
|
|
mDC->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::StrokeLine(const Point &aStart,
|
|
const Point &aEnd,
|
|
const Pattern &aPattern,
|
|
const StrokeOptions &aStrokeOptions,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
|
|
|
|
mDC->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::Stroke(const Path *aPath,
|
|
const Pattern &aPattern,
|
|
const StrokeOptions &aStrokeOptions,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
|
|
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
|
|
return;
|
|
}
|
|
const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
|
|
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
|
|
|
|
mDC->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::Fill(const Path *aPath,
|
|
const Pattern &aPattern,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
|
|
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
|
|
return;
|
|
}
|
|
const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
|
|
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
|
|
mDC->FillGeometry(d2dPath->mGeometry, brush);
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
|
|
const GlyphBuffer &aBuffer,
|
|
const Pattern &aPattern,
|
|
const DrawOptions &aOptions,
|
|
const GlyphRenderingOptions *aRenderingOptions)
|
|
{
|
|
if (aFont->GetType() != FontType::DWRITE) {
|
|
gfxDebug() << *this << ": Ignoring drawing call for incompatible font.";
|
|
return;
|
|
}
|
|
|
|
ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont);
|
|
|
|
IDWriteRenderingParams *params = nullptr;
|
|
if (aRenderingOptions) {
|
|
if (aRenderingOptions->GetType() != FontType::DWRITE) {
|
|
gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions.";
|
|
// This should never happen.
|
|
MOZ_ASSERT(false);
|
|
} else {
|
|
params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderingOptions)->mParams;
|
|
}
|
|
}
|
|
|
|
AntialiasMode aaMode = font->GetDefaultAAMode();
|
|
|
|
if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
|
|
aaMode = aOptions.mAntialiasMode;
|
|
}
|
|
|
|
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
|
|
|
|
bool forceClearType = false;
|
|
if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA &&
|
|
aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) {
|
|
forceClearType = true;
|
|
}
|
|
|
|
|
|
D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
|
|
switch (aaMode) {
|
|
case AntialiasMode::NONE:
|
|
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
break;
|
|
case AntialiasMode::GRAY:
|
|
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
break;
|
|
case AntialiasMode::SUBPIXEL:
|
|
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
break;
|
|
default:
|
|
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
}
|
|
|
|
if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
|
|
mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) {
|
|
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
}
|
|
|
|
mDC->SetTextAntialiasMode(d2dAAMode);
|
|
|
|
if (params != mTextRenderingParams) {
|
|
mDC->SetTextRenderingParams(params);
|
|
mTextRenderingParams = params;
|
|
}
|
|
|
|
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
|
|
|
|
AutoDWriteGlyphRun autoRun;
|
|
DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
|
|
|
|
bool needsRepushedLayers = false;
|
|
if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && mFormat != SurfaceFormat::B8G8R8X8) {
|
|
D2D1_RECT_F rect;
|
|
bool isAligned;
|
|
needsRepushedLayers = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
|
|
|
|
// If we have a complex clip in our stack and we have a transparent
|
|
// background, and subpixel AA is permitted, we need to repush our layer
|
|
// stack limited by the glyph run bounds initializing our layers for
|
|
// subpixel AA.
|
|
if (needsRepushedLayers) {
|
|
mDC->GetGlyphRunWorldBounds(D2D1::Point2F(), &autoRun,
|
|
DWRITE_MEASURING_MODE_NATURAL, &rect);
|
|
rect.left = std::floor(rect.left);
|
|
rect.right = std::ceil(rect.right);
|
|
rect.top = std::floor(rect.top);
|
|
rect.bottom = std::ceil(rect.bottom);
|
|
|
|
PopAllClips();
|
|
|
|
if (!mTransform.IsRectilinear()) {
|
|
// We must limit the pixels we touch to the -user space- bounds of
|
|
// the glyphs being drawn. In order not to get transparent pixels
|
|
// copied up in our pushed layer stack.
|
|
D2D1_RECT_F userRect;
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mDC->GetGlyphRunWorldBounds(D2D1::Point2F(), &autoRun,
|
|
DWRITE_MEASURING_MODE_NATURAL, &userRect);
|
|
|
|
RefPtr<ID2D1PathGeometry> path;
|
|
D2DFactory()->CreatePathGeometry(getter_AddRefs(path));
|
|
RefPtr<ID2D1GeometrySink> sink;
|
|
path->Open(getter_AddRefs(sink));
|
|
sink->BeginFigure(D2D1::Point2F(userRect.left, userRect.top), D2D1_FIGURE_BEGIN_FILLED);
|
|
sink->AddLine(D2D1::Point2F(userRect.right, userRect.top));
|
|
sink->AddLine(D2D1::Point2F(userRect.right, userRect.bottom));
|
|
sink->AddLine(D2D1::Point2F(userRect.left, userRect.bottom));
|
|
sink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
|
sink->Close();
|
|
|
|
mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), path, D2D1_ANTIALIAS_MODE_ALIASED,
|
|
D2DMatrix(mTransform), 1.0f, nullptr,
|
|
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND |
|
|
D2D1_LAYER_OPTIONS1_IGNORE_ALPHA), nullptr);
|
|
}
|
|
|
|
PushClipsToDC(mDC, true, rect);
|
|
mDC->SetTransform(D2DMatrix(mTransform));
|
|
}
|
|
}
|
|
|
|
if (brush) {
|
|
mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
|
|
}
|
|
|
|
if (needsRepushedLayers) {
|
|
PopClipsFromDC(mDC);
|
|
|
|
if (!mTransform.IsRectilinear()) {
|
|
mDC->PopLayer();
|
|
}
|
|
}
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::Mask(const Pattern &aSource,
|
|
const Pattern &aMask,
|
|
const DrawOptions &aOptions)
|
|
{
|
|
PrepareForDrawing(aOptions.mCompositionOp, aSource);
|
|
|
|
RefPtr<ID2D1Brush> source = CreateBrushForPattern(aSource, aOptions.mAlpha);
|
|
RefPtr<ID2D1Brush> mask = CreateBrushForPattern(aMask, 1.0f);
|
|
mDC->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr,
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
D2D1::IdentityMatrix(),
|
|
1.0f, mask),
|
|
nullptr);
|
|
|
|
Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height);
|
|
Matrix mat = mTransform;
|
|
mat.Invert();
|
|
|
|
mDC->FillRectangle(D2DRect(mat.TransformBounds(rect)), source);
|
|
|
|
mDC->PopLayer();
|
|
|
|
FinalizeDrawing(aOptions.mCompositionOp, aSource);
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PushClip(const Path *aPath)
|
|
{
|
|
if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
|
|
gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
|
|
return;
|
|
}
|
|
|
|
mCurrentClippedGeometry = nullptr;
|
|
|
|
RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
|
|
|
|
PushedClip clip;
|
|
clip.mTransform = D2DMatrix(mTransform);
|
|
clip.mPath = pathD2D;
|
|
|
|
pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
|
|
|
|
mPushedClips.push_back(clip);
|
|
|
|
// The transform of clips is relative to the world matrix, since we use the total
|
|
// transform for the clips, make the world matrix identity.
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
if (mClipsArePushed) {
|
|
PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform);
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PushClipRect(const Rect &aRect)
|
|
{
|
|
if (!mTransform.IsRectilinear()) {
|
|
// Whoops, this isn't a rectangle in device space, Direct2D will not deal
|
|
// with this transform the way we want it to.
|
|
// See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
|
|
|
|
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
|
pathBuilder->MoveTo(aRect.TopLeft());
|
|
pathBuilder->LineTo(aRect.TopRight());
|
|
pathBuilder->LineTo(aRect.BottomRight());
|
|
pathBuilder->LineTo(aRect.BottomLeft());
|
|
pathBuilder->Close();
|
|
RefPtr<Path> path = pathBuilder->Finish();
|
|
return PushClip(path);
|
|
}
|
|
|
|
mCurrentClippedGeometry = nullptr;
|
|
|
|
PushedClip clip;
|
|
Rect rect = mTransform.TransformBounds(aRect);
|
|
IntRect intRect;
|
|
clip.mIsPixelAligned = rect.ToIntRect(&intRect);
|
|
|
|
// Do not store the transform, just store the device space rectangle directly.
|
|
clip.mBounds = D2DRect(rect);
|
|
|
|
mPushedClips.push_back(clip);
|
|
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
if (mClipsArePushed) {
|
|
mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PopClip()
|
|
{
|
|
mCurrentClippedGeometry = nullptr;
|
|
|
|
if (mClipsArePushed) {
|
|
if (mPushedClips.back().mPath) {
|
|
mDC->PopLayer();
|
|
} else {
|
|
mDC->PopAxisAlignedClip();
|
|
}
|
|
}
|
|
mPushedClips.pop_back();
|
|
}
|
|
|
|
already_AddRefed<SourceSurface>
|
|
DrawTargetD2D1::CreateSourceSurfaceFromData(unsigned char *aData,
|
|
const IntSize &aSize,
|
|
int32_t aStride,
|
|
SurfaceFormat aFormat) const
|
|
{
|
|
RefPtr<ID2D1Bitmap1> bitmap;
|
|
|
|
HRESULT hr = mDC->CreateBitmap(D2DIntSize(aSize), aData, aStride,
|
|
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(aFormat)),
|
|
getter_AddRefs(bitmap));
|
|
|
|
if (FAILED(hr) || !bitmap) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D2D1.1] 1CreateBitmap failure " << aSize << " Code: " << hexa(hr) << " format " << (int)aFormat;
|
|
return nullptr;
|
|
}
|
|
|
|
return MakeAndAddRef<SourceSurfaceD2D1>(bitmap.get(), mDC, aFormat, aSize);
|
|
}
|
|
|
|
already_AddRefed<DrawTarget>
|
|
DrawTargetD2D1::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
|
|
{
|
|
RefPtr<DrawTargetD2D1> dt = new DrawTargetD2D1();
|
|
|
|
if (!dt->Init(aSize, aFormat)) {
|
|
return nullptr;
|
|
}
|
|
|
|
return dt.forget();
|
|
}
|
|
|
|
already_AddRefed<PathBuilder>
|
|
DrawTargetD2D1::CreatePathBuilder(FillRule aFillRule) const
|
|
{
|
|
RefPtr<ID2D1PathGeometry> path;
|
|
HRESULT hr = factory()->CreatePathGeometry(getter_AddRefs(path));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << *this << ": Failed to create Direct2D Path Geometry. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<ID2D1GeometrySink> sink;
|
|
hr = path->Open(getter_AddRefs(sink));
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << *this << ": Failed to access Direct2D Path Geometry. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
|
|
if (aFillRule == FillRule::FILL_WINDING) {
|
|
sink->SetFillMode(D2D1_FILL_MODE_WINDING);
|
|
}
|
|
|
|
return MakeAndAddRef<PathBuilderD2D>(sink, path, aFillRule, BackendType::DIRECT2D1_1);
|
|
}
|
|
|
|
already_AddRefed<GradientStops>
|
|
DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
|
|
{
|
|
if (aNumStops == 0) {
|
|
gfxWarning() << *this << ": Failed to create GradientStopCollection with no stops.";
|
|
return nullptr;
|
|
}
|
|
|
|
D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
|
|
|
|
for (uint32_t i = 0; i < aNumStops; i++) {
|
|
stops[i].position = rawStops[i].offset;
|
|
stops[i].color = D2DColor(rawStops[i].color);
|
|
}
|
|
|
|
RefPtr<ID2D1GradientStopCollection> stopCollection;
|
|
|
|
HRESULT hr =
|
|
mDC->CreateGradientStopCollection(stops, aNumStops,
|
|
D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
|
|
getter_AddRefs(stopCollection));
|
|
delete [] stops;
|
|
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << *this << ": Failed to create GradientStopCollection. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
|
|
return MakeAndAddRef<GradientStopsD2D>(stopCollection, Factory::GetDirect3D11Device());
|
|
}
|
|
|
|
already_AddRefed<FilterNode>
|
|
DrawTargetD2D1::CreateFilter(FilterType aType)
|
|
{
|
|
return FilterNodeD2D1::Create(mDC, aType);
|
|
}
|
|
|
|
bool
|
|
DrawTargetD2D1::Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ID2D1Device* device = Factory::GetD2D1Device();
|
|
if (!device) {
|
|
return false;
|
|
}
|
|
|
|
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, getter_AddRefs(mDC));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() <<"[D2D1.1] 1Failed to create a DeviceContext, code: " << hexa(hr) << " format " << (int)aFormat;
|
|
return false;
|
|
}
|
|
|
|
RefPtr<IDXGISurface> dxgiSurface;
|
|
aTexture->QueryInterface(__uuidof(IDXGISurface),
|
|
(void**)((IDXGISurface**)getter_AddRefs(dxgiSurface)));
|
|
if (!dxgiSurface) {
|
|
gfxCriticalError() <<"[D2D1.1] Failed to obtain a DXGI surface.";
|
|
return false;
|
|
}
|
|
|
|
D2D1_BITMAP_PROPERTIES1 props;
|
|
props.dpiX = 96;
|
|
props.dpiY = 96;
|
|
props.pixelFormat = D2DPixelFormat(aFormat);
|
|
props.colorContext = nullptr;
|
|
props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
|
|
hr = mDC->CreateBitmapFromDxgiSurface(dxgiSurface, props, (ID2D1Bitmap1**)getter_AddRefs(mBitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() << "[D2D1.1] CreateBitmapFromDxgiSurface failure Code: " << hexa(hr) << " format " << (int)aFormat;
|
|
return false;
|
|
}
|
|
|
|
mFormat = aFormat;
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
aTexture->GetDesc(&desc);
|
|
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
mSize.width = desc.Width;
|
|
mSize.height = desc.Height;
|
|
props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
|
hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 2CreateBitmap failure " << mSize << " Code: " << hexa(hr);
|
|
return false;
|
|
}
|
|
|
|
// This single solid color brush system is not very 'threadsafe', however,
|
|
// issueing multiple drawing commands simultaneously to a single drawtarget
|
|
// from multiple threads is unexpected since there's no way to guarantee
|
|
// ordering in that situation anyway.
|
|
hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() << "[D2D1.1] Failure creating solid color brush.";
|
|
return false;
|
|
}
|
|
|
|
mDC->SetTarget(mBitmap);
|
|
|
|
mDC->BeginDraw();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ID2D1Device* device = Factory::GetD2D1Device();
|
|
if (!device) {
|
|
return false;
|
|
}
|
|
|
|
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, getter_AddRefs(mDC));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() <<"[D2D1.1] 2Failed to create a DeviceContext, code: " << hexa(hr) << " format " << (int)aFormat;
|
|
return false;
|
|
}
|
|
|
|
if (mDC->GetMaximumBitmapSize() < UINT32(aSize.width) ||
|
|
mDC->GetMaximumBitmapSize() < UINT32(aSize.height)) {
|
|
// This is 'ok', so don't assert
|
|
gfxCriticalNote << "[D2D1.1] Attempt to use unsupported surface size " << aSize;
|
|
return false;
|
|
}
|
|
|
|
D2D1_BITMAP_PROPERTIES1 props;
|
|
props.dpiX = 96;
|
|
props.dpiY = 96;
|
|
props.pixelFormat = D2DPixelFormat(aFormat);
|
|
props.colorContext = nullptr;
|
|
props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
|
|
hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mBitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() << "[D2D1.1] 3CreateBitmap failure " << aSize << " Code: " << hexa(hr) << " format " << (int)aFormat;
|
|
return false;
|
|
}
|
|
|
|
props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
|
hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D2D1.1] failed to create new TempBitmap " << aSize << " Code: " << hexa(hr);
|
|
return false;
|
|
}
|
|
|
|
mDC->SetTarget(mBitmap);
|
|
|
|
hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError() << "[D2D1.1] Failure creating solid color brush.";
|
|
return false;
|
|
}
|
|
|
|
mDC->BeginDraw();
|
|
|
|
mDC->Clear();
|
|
|
|
mFormat = aFormat;
|
|
mSize = aSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Private helpers.
|
|
*/
|
|
uint32_t
|
|
DrawTargetD2D1::GetByteSize() const
|
|
{
|
|
return mSize.width * mSize.height * BytesPerPixel(mFormat);
|
|
}
|
|
|
|
ID2D1Factory1*
|
|
DrawTargetD2D1::factory()
|
|
{
|
|
if (mFactory) {
|
|
return mFactory;
|
|
}
|
|
|
|
ID2D1Factory* d2dFactory = D2DFactory();
|
|
if (!d2dFactory) {
|
|
return nullptr;
|
|
}
|
|
|
|
HRESULT hr = d2dFactory->QueryInterface((ID2D1Factory1**)&mFactory);
|
|
|
|
if (FAILED(hr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
RadialGradientEffectD2D1::Register(mFactory);
|
|
|
|
return mFactory;
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::CleanupD2D()
|
|
{
|
|
if (mFactory) {
|
|
RadialGradientEffectD2D1::Unregister(mFactory);
|
|
mFactory->Release();
|
|
mFactory = nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::MarkChanged()
|
|
{
|
|
if (mSnapshot) {
|
|
if (mSnapshot->hasOneRef()) {
|
|
// Just destroy it, since no-one else knows about it.
|
|
mSnapshot = nullptr;
|
|
} else {
|
|
mSnapshot->DrawTargetWillChange();
|
|
// The snapshot will no longer depend on this target.
|
|
MOZ_ASSERT(!mSnapshot);
|
|
}
|
|
}
|
|
if (mDependentTargets.size()) {
|
|
// Copy mDependentTargets since the Flush()es below will modify it.
|
|
TargetSet tmpTargets = mDependentTargets;
|
|
for (TargetSet::iterator iter = tmpTargets.begin();
|
|
iter != tmpTargets.end(); iter++) {
|
|
(*iter)->Flush();
|
|
}
|
|
// The Flush() should have broken all dependencies on this target.
|
|
MOZ_ASSERT(!mDependentTargets.size());
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|
{
|
|
MarkChanged();
|
|
|
|
if (D2DSupportsPrimitiveBlendMode(aOp) && IsPatternSupportedByD2D(aPattern)) {
|
|
// It's important to do this before FlushTransformToDC! As this will cause
|
|
// the transform to become dirty.
|
|
PushAllClips();
|
|
|
|
FlushTransformToDC();
|
|
|
|
if (aOp != CompositionOp::OP_OVER)
|
|
mDC->SetPrimitiveBlend(D2DPrimitiveBlendMode(aOp));
|
|
|
|
return;
|
|
}
|
|
|
|
PopAllClips();
|
|
|
|
mDC->SetTarget(mTempBitmap);
|
|
mDC->Clear(D2D1::ColorF(0, 0));
|
|
|
|
PushAllClips();
|
|
FlushTransformToDC();
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|
{
|
|
bool patternSupported = IsPatternSupportedByD2D(aPattern);
|
|
|
|
if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
|
|
if (aOp != CompositionOp::OP_OVER)
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
|
|
return;
|
|
}
|
|
|
|
PopAllClips();
|
|
|
|
RefPtr<ID2D1Image> image;
|
|
mDC->GetTarget(getter_AddRefs(image));
|
|
|
|
mDC->SetTarget(mBitmap);
|
|
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
if (patternSupported) {
|
|
if (D2DSupportsCompositeMode(aOp)) {
|
|
D2D1_RECT_F rect;
|
|
bool isAligned;
|
|
RefPtr<ID2D1Bitmap> tmpBitmap;
|
|
bool clipIsComplex = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
|
|
|
|
if (clipIsComplex) {
|
|
if (!IsOperatorBoundByMask(aOp)) {
|
|
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), getter_AddRefs(tmpBitmap));
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 6CreateBitmap failure " << mSize << " Code: " << hexa(hr) << " format " << (int)mFormat;
|
|
// For now, crash in this scenario; this should happen because tmpBitmap is
|
|
// null and CopyFromBitmap call below dereferences it.
|
|
// return;
|
|
}
|
|
mDC->Flush();
|
|
|
|
tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
|
|
}
|
|
} else {
|
|
PushAllClips();
|
|
}
|
|
mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
|
|
|
|
if (tmpBitmap) {
|
|
RefPtr<ID2D1BitmapBrush> brush;
|
|
RefPtr<ID2D1Geometry> inverseGeom = GetInverseClippedGeometry();
|
|
mDC->CreateBitmapBrush(tmpBitmap, getter_AddRefs(brush));
|
|
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
|
|
mDC->FillGeometry(inverseGeom, brush);
|
|
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!mBlendEffect) {
|
|
HRESULT hr = mDC->CreateEffect(CLSID_D2D1Blend, getter_AddRefs(mBlendEffect));
|
|
|
|
if (FAILED(hr) || !mBlendEffect) {
|
|
gfxWarning() << "Failed to create blend effect!";
|
|
return;
|
|
}
|
|
}
|
|
|
|
RefPtr<ID2D1Bitmap> tmpBitmap;
|
|
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), getter_AddRefs(tmpBitmap));
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 5CreateBitmap failure " << mSize << " Code: " << hexa(hr) << " format " << (int)mFormat;
|
|
return;
|
|
}
|
|
|
|
// This flush is important since the copy method will not know about the context drawing to the surface.
|
|
// We also need to pop all the clips to make sure any drawn content will have made it to the final bitmap.
|
|
mDC->Flush();
|
|
|
|
// We need to use a copy here because affects don't accept a surface on
|
|
// both their in- and outputs.
|
|
tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
|
|
|
|
mBlendEffect->SetInput(0, tmpBitmap);
|
|
mBlendEffect->SetInput(1, mTempBitmap);
|
|
mBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
|
|
|
|
PushAllClips();
|
|
|
|
mDC->DrawImage(mBlendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
|
|
return;
|
|
}
|
|
|
|
const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
|
|
if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
|
|
// Draw nothing!
|
|
return;
|
|
}
|
|
|
|
PushAllClips();
|
|
|
|
RefPtr<ID2D1Effect> radialGradientEffect;
|
|
|
|
HRESULT hr = mDC->CreateEffect(CLSID_RadialGradientEffect, getter_AddRefs(radialGradientEffect));
|
|
if (FAILED(hr) || !radialGradientEffect) {
|
|
gfxWarning() << "Failed to create radial gradient effect. Code: " << hexa(hr);
|
|
return;
|
|
}
|
|
|
|
radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION,
|
|
static_cast<const GradientStopsD2D*>(pat->mStops.get())->mStopCollection);
|
|
radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y));
|
|
radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y));
|
|
radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1);
|
|
radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
|
|
radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
|
|
radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform));
|
|
radialGradientEffect->SetInput(0, image);
|
|
|
|
mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::AddDependencyOnSource(SourceSurfaceD2D1* aSource)
|
|
{
|
|
if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
|
|
aSource->mDrawTarget->mDependentTargets.insert(this);
|
|
mDependingOnTargets.insert(aSource->mDrawTarget);
|
|
}
|
|
}
|
|
|
|
static D2D1_RECT_F
|
|
IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
|
|
{
|
|
D2D1_RECT_F result;
|
|
result.left = max(aRect1.left, aRect2.left);
|
|
result.top = max(aRect1.top, aRect2.top);
|
|
result.right = min(aRect1.right, aRect2.right);
|
|
result.bottom = min(aRect1.bottom, aRect2.bottom);
|
|
|
|
result.right = max(result.right, result.left);
|
|
result.bottom = max(result.bottom, result.top);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
DrawTargetD2D1::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned)
|
|
{
|
|
if (!mPushedClips.size()) {
|
|
return false;
|
|
}
|
|
|
|
aClipRect = D2D1::RectF(0, 0, mSize.width, mSize.height);
|
|
for (auto iter = mPushedClips.begin();iter != mPushedClips.end(); iter++) {
|
|
if (iter->mPath) {
|
|
return false;
|
|
}
|
|
aClipRect = IntersectRect(aClipRect, iter->mBounds);
|
|
if (!iter->mIsPixelAligned) {
|
|
aIsPixelAligned = false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
already_AddRefed<ID2D1Geometry>
|
|
DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
|
|
{
|
|
if (mCurrentClippedGeometry) {
|
|
*aClipBounds = mCurrentClipBounds;
|
|
RefPtr<ID2D1Geometry> clippedGeometry(mCurrentClippedGeometry);
|
|
return clippedGeometry.forget();
|
|
}
|
|
|
|
MOZ_ASSERT(mPushedClips.size());
|
|
|
|
mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
|
|
|
|
// if pathGeom is null then pathRect represents the path.
|
|
RefPtr<ID2D1Geometry> pathGeom;
|
|
D2D1_RECT_F pathRect;
|
|
bool pathRectIsAxisAligned = false;
|
|
auto iter = mPushedClips.begin();
|
|
|
|
if (iter->mPath) {
|
|
pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
|
|
} else {
|
|
pathRect = iter->mBounds;
|
|
pathRectIsAxisAligned = iter->mIsPixelAligned;
|
|
}
|
|
|
|
iter++;
|
|
for (;iter != mPushedClips.end(); iter++) {
|
|
// Do nothing but add it to the current clip bounds.
|
|
if (!iter->mPath && iter->mIsPixelAligned) {
|
|
mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
|
|
IntRect(int32_t(iter->mBounds.left), int32_t(iter->mBounds.top),
|
|
int32_t(iter->mBounds.right - iter->mBounds.left),
|
|
int32_t(iter->mBounds.bottom - iter->mBounds.top)));
|
|
continue;
|
|
}
|
|
|
|
if (!pathGeom) {
|
|
if (pathRectIsAxisAligned) {
|
|
mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
|
|
IntRect(int32_t(pathRect.left), int32_t(pathRect.top),
|
|
int32_t(pathRect.right - pathRect.left),
|
|
int32_t(pathRect.bottom - pathRect.top)));
|
|
}
|
|
if (iter->mPath) {
|
|
// See if pathRect needs to go into the path geometry.
|
|
if (!pathRectIsAxisAligned) {
|
|
pathGeom = ConvertRectToGeometry(pathRect);
|
|
} else {
|
|
pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
|
|
}
|
|
} else {
|
|
pathRect = IntersectRect(pathRect, iter->mBounds);
|
|
pathRectIsAxisAligned = false;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
RefPtr<ID2D1PathGeometry> newGeom;
|
|
factory()->CreatePathGeometry(getter_AddRefs(newGeom));
|
|
|
|
RefPtr<ID2D1GeometrySink> currentSink;
|
|
newGeom->Open(getter_AddRefs(currentSink));
|
|
|
|
if (iter->mPath) {
|
|
pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
|
|
iter->mTransform, currentSink);
|
|
} else {
|
|
RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
|
|
pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
|
|
D2D1::IdentityMatrix(), currentSink);
|
|
}
|
|
|
|
currentSink->Close();
|
|
|
|
pathGeom = newGeom.forget();
|
|
}
|
|
|
|
// For now we need mCurrentClippedGeometry to always be non-nullptr. This
|
|
// method might seem a little strange but it is just fine, if pathGeom is
|
|
// nullptr pathRect will always still contain 1 clip unaccounted for
|
|
// regardless of mCurrentClipBounds.
|
|
if (!pathGeom) {
|
|
pathGeom = ConvertRectToGeometry(pathRect);
|
|
}
|
|
mCurrentClippedGeometry = pathGeom.forget();
|
|
*aClipBounds = mCurrentClipBounds;
|
|
RefPtr<ID2D1Geometry> clippedGeometry(mCurrentClippedGeometry);
|
|
return clippedGeometry.forget();
|
|
}
|
|
|
|
already_AddRefed<ID2D1Geometry>
|
|
DrawTargetD2D1::GetInverseClippedGeometry()
|
|
{
|
|
IntRect bounds;
|
|
RefPtr<ID2D1Geometry> geom = GetClippedGeometry(&bounds);
|
|
RefPtr<ID2D1RectangleGeometry> rectGeom;
|
|
RefPtr<ID2D1PathGeometry> inverseGeom;
|
|
|
|
factory()->CreateRectangleGeometry(D2D1::RectF(0, 0, mSize.width, mSize.height), getter_AddRefs(rectGeom));
|
|
factory()->CreatePathGeometry(getter_AddRefs(inverseGeom));
|
|
RefPtr<ID2D1GeometrySink> sink;
|
|
inverseGeom->Open(getter_AddRefs(sink));
|
|
rectGeom->CombineWithGeometry(geom, D2D1_COMBINE_MODE_EXCLUDE, D2D1::IdentityMatrix(), sink);
|
|
sink->Close();
|
|
|
|
return inverseGeom.forget();
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PopAllClips()
|
|
{
|
|
if (mClipsArePushed) {
|
|
PopClipsFromDC(mDC);
|
|
|
|
mClipsArePushed = false;
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PushAllClips()
|
|
{
|
|
if (!mClipsArePushed) {
|
|
PushClipsToDC(mDC);
|
|
|
|
mClipsArePushed = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC, bool aForceIgnoreAlpha, const D2D1_RECT_F& aMaxRect)
|
|
{
|
|
mDC->SetTransform(D2D1::IdentityMatrix());
|
|
mTransformDirty = true;
|
|
|
|
for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
|
|
iter != mPushedClips.end(); iter++) {
|
|
if (iter->mPath) {
|
|
PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform, aForceIgnoreAlpha, aMaxRect);
|
|
} else {
|
|
mDC->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC)
|
|
{
|
|
for (int i = mPushedClips.size() - 1; i >= 0; i--) {
|
|
if (mPushedClips[i].mPath) {
|
|
aDC->PopLayer();
|
|
} else {
|
|
aDC->PopAxisAlignedClip();
|
|
}
|
|
}
|
|
}
|
|
|
|
already_AddRefed<ID2D1Brush>
|
|
DrawTargetD2D1::CreateTransparentBlackBrush()
|
|
{
|
|
return GetSolidColorBrush(D2D1::ColorF(0, 0));
|
|
}
|
|
|
|
already_AddRefed<ID2D1SolidColorBrush>
|
|
DrawTargetD2D1::GetSolidColorBrush(const D2D_COLOR_F& aColor)
|
|
{
|
|
RefPtr<ID2D1SolidColorBrush> brush = mSolidColorBrush;
|
|
brush->SetColor(aColor);
|
|
return brush.forget();
|
|
}
|
|
|
|
already_AddRefed<ID2D1Brush>
|
|
DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|
{
|
|
if (!IsPatternSupportedByD2D(aPattern)) {
|
|
return GetSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f));
|
|
}
|
|
|
|
if (aPattern.GetType() == PatternType::COLOR) {
|
|
Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
|
|
return GetSolidColorBrush(D2D1::ColorF(color.r, color.g, color.b, color.a * aAlpha));
|
|
}
|
|
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
|
RefPtr<ID2D1LinearGradientBrush> gradBrush;
|
|
const LinearGradientPattern *pat =
|
|
static_cast<const LinearGradientPattern*>(&aPattern);
|
|
|
|
GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
|
|
|
|
if (!stops) {
|
|
gfxDebug() << "No stops specified for gradient pattern.";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
if (pat->mBegin == pat->mEnd) {
|
|
uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
|
|
vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
|
|
stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
|
|
d2dStops.back().color.a *= aAlpha;
|
|
return GetSolidColorBrush(d2dStops.back().color);
|
|
}
|
|
|
|
mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
|
|
D2DPoint(pat->mEnd)),
|
|
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
|
|
stops->mStopCollection,
|
|
getter_AddRefs(gradBrush));
|
|
|
|
if (!gradBrush) {
|
|
gfxWarning() << "Couldn't create gradient brush.";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
return gradBrush.forget();
|
|
}
|
|
if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
|
RefPtr<ID2D1RadialGradientBrush> gradBrush;
|
|
const RadialGradientPattern *pat =
|
|
static_cast<const RadialGradientPattern*>(&aPattern);
|
|
|
|
GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
|
|
|
|
if (!stops) {
|
|
gfxDebug() << "No stops specified for gradient pattern.";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
// This will not be a complex radial gradient brush.
|
|
mDC->CreateRadialGradientBrush(
|
|
D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2),
|
|
D2DPoint(pat->mCenter1 - pat->mCenter2),
|
|
pat->mRadius2, pat->mRadius2),
|
|
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
|
|
stops->mStopCollection,
|
|
getter_AddRefs(gradBrush));
|
|
|
|
if (!gradBrush) {
|
|
gfxWarning() << "Couldn't create gradient brush.";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
return gradBrush.forget();
|
|
}
|
|
if (aPattern.GetType() == PatternType::SURFACE) {
|
|
const SurfacePattern *pat =
|
|
static_cast<const SurfacePattern*>(&aPattern);
|
|
|
|
if (!pat->mSurface) {
|
|
gfxDebug() << "No source surface specified for surface pattern";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
D2D1_RECT_F samplingBounds;
|
|
Matrix mat = pat->mMatrix;
|
|
|
|
MOZ_ASSERT(pat->mSurface->IsValid());
|
|
|
|
RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr);
|
|
|
|
if (!image) {
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
bool useSamplingRect = false;
|
|
if (pat->mSamplingRect.IsEmpty()) {
|
|
RefPtr<ID2D1Bitmap> bitmap;
|
|
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
|
|
if (bitmap) {
|
|
RefPtr<ID2D1BitmapBrush> bitmapBrush;
|
|
mDC->CreateBitmapBrush(bitmap,
|
|
D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
|
|
D2DExtend(pat->mExtendMode),
|
|
D2DFilter(pat->mFilter)),
|
|
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
|
getter_AddRefs(bitmapBrush));
|
|
if (!bitmapBrush) {
|
|
gfxWarning() << "Couldn't create bitmap brush!";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
return bitmapBrush.forget();
|
|
}
|
|
}
|
|
|
|
RefPtr<ID2D1ImageBrush> imageBrush;
|
|
if (pat->mSamplingRect.IsEmpty()) {
|
|
samplingBounds = D2D1::RectF(0, 0,
|
|
Float(pat->mSurface->GetSize().width),
|
|
Float(pat->mSurface->GetSize().height));
|
|
} else if (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
|
|
samplingBounds = D2DRect(pat->mSamplingRect);
|
|
mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y);
|
|
} else {
|
|
// We will do a partial upload of the sampling restricted area from GetImageForSurface.
|
|
samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height);
|
|
}
|
|
mDC->CreateImageBrush(image,
|
|
D2D1::ImageBrushProperties(samplingBounds,
|
|
D2DExtend(pat->mExtendMode),
|
|
D2DExtend(pat->mExtendMode),
|
|
D2DInterpolationMode(pat->mFilter)),
|
|
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
|
getter_AddRefs(imageBrush));
|
|
|
|
if (!imageBrush) {
|
|
gfxWarning() << "Couldn't create image brush!";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
return imageBrush.forget();
|
|
}
|
|
|
|
gfxWarning() << "Invalid pattern type detected.";
|
|
return CreateTransparentBlackBrush();
|
|
}
|
|
|
|
already_AddRefed<ID2D1Image>
|
|
DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform,
|
|
ExtendMode aExtendMode, const IntRect* aSourceRect)
|
|
{
|
|
RefPtr<ID2D1Image> image;
|
|
|
|
switch (aSurface->GetType()) {
|
|
case SurfaceType::D2D1_1_IMAGE:
|
|
{
|
|
SourceSurfaceD2D1 *surf = static_cast<SourceSurfaceD2D1*>(aSurface);
|
|
image = surf->GetImage();
|
|
AddDependencyOnSource(surf);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface();
|
|
if (!dataSurf) {
|
|
gfxWarning() << "Invalid surface type.";
|
|
return nullptr;
|
|
}
|
|
return CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode,
|
|
aSourceTransform, mDC, aSourceRect);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return image.forget();
|
|
}
|
|
|
|
already_AddRefed<SourceSurface>
|
|
DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
|
|
{
|
|
if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
|
|
RefPtr<SourceSurface> surface(aSurface);
|
|
return surface.forget();
|
|
}
|
|
|
|
RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
|
|
|
|
RefPtr<ID2D1Bitmap1> bitmap;
|
|
{
|
|
DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
|
|
if (MOZ2D_WARN_IF(!map.IsMapped())) {
|
|
return nullptr;
|
|
}
|
|
|
|
HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.GetData(), map.GetStride(),
|
|
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
|
|
getter_AddRefs(bitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(data->GetSize()))) << "[D2D1.1] 4CreateBitmap failure " << data->GetSize() << " Code: " << hexa(hr) << " format " << (int)data->GetFormat();
|
|
}
|
|
}
|
|
|
|
if (!bitmap) {
|
|
return data.forget();
|
|
}
|
|
|
|
return MakeAndAddRef<SourceSurfaceD2D1>(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
|
|
}
|
|
|
|
void
|
|
DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform,
|
|
bool aForceIgnoreAlpha, const D2D1_RECT_F& aMaxRect)
|
|
{
|
|
D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
|
|
|
|
if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE || aForceIgnoreAlpha) {
|
|
options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
|
|
}
|
|
|
|
mDC->PushLayer(D2D1::LayerParameters1(aMaxRect, aGeometry,
|
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
|
|
1.0, nullptr, options), nullptr);
|
|
}
|
|
|
|
}
|
|
}
|