Files
palemoon27/gfx/2d/DrawTargetD2D1.cpp
T
roytam1 8637eba4b3 import changes from `dev' branch of rmottola/Arctic-Fox:
- 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)
2022-12-16 11:12:33 +08:00

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);
}
}
}