Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=4 et sw=4 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "mozilla/ArrayUtils.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "gfxWindowsPlatform.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "gfxImageSurface.h" |
michael@0 | 12 | #include "gfxWindowsSurface.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "nsUnicharUtils.h" |
michael@0 | 15 | |
michael@0 | 16 | #include "mozilla/Preferences.h" |
michael@0 | 17 | #include "mozilla/WindowsVersion.h" |
michael@0 | 18 | #include "nsServiceManagerUtils.h" |
michael@0 | 19 | #include "nsTArray.h" |
michael@0 | 20 | |
michael@0 | 21 | #include "nsIWindowsRegKey.h" |
michael@0 | 22 | #include "nsIFile.h" |
michael@0 | 23 | #include "plbase64.h" |
michael@0 | 24 | #include "nsIXULRuntime.h" |
michael@0 | 25 | |
michael@0 | 26 | #include "nsIGfxInfo.h" |
michael@0 | 27 | |
michael@0 | 28 | #include "gfxCrashReporterUtils.h" |
michael@0 | 29 | |
michael@0 | 30 | #include "gfxGDIFontList.h" |
michael@0 | 31 | #include "gfxGDIFont.h" |
michael@0 | 32 | |
michael@0 | 33 | #include "mozilla/layers/CompositorParent.h" // for CompositorParent::IsInCompositorThread |
michael@0 | 34 | #include "DeviceManagerD3D9.h" |
michael@0 | 35 | |
michael@0 | 36 | #include "WinUtils.h" |
michael@0 | 37 | |
michael@0 | 38 | #ifdef CAIRO_HAS_DWRITE_FONT |
michael@0 | 39 | #include "gfxDWriteFontList.h" |
michael@0 | 40 | #include "gfxDWriteFonts.h" |
michael@0 | 41 | #include "gfxDWriteCommon.h" |
michael@0 | 42 | #include <dwrite.h> |
michael@0 | 43 | #endif |
michael@0 | 44 | |
michael@0 | 45 | #include "gfxUserFontSet.h" |
michael@0 | 46 | #include "nsWindowsHelpers.h" |
michael@0 | 47 | #include "gfx2DGlue.h" |
michael@0 | 48 | |
michael@0 | 49 | #include <string> |
michael@0 | 50 | |
michael@0 | 51 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 52 | #include "gfxD2DSurface.h" |
michael@0 | 53 | |
michael@0 | 54 | #include <d3d10_1.h> |
michael@0 | 55 | |
michael@0 | 56 | #include "mozilla/gfx/2D.h" |
michael@0 | 57 | |
michael@0 | 58 | #include "nsMemory.h" |
michael@0 | 59 | #endif |
michael@0 | 60 | |
michael@0 | 61 | #include <d3d11.h> |
michael@0 | 62 | |
michael@0 | 63 | #include "nsIMemoryReporter.h" |
michael@0 | 64 | #include <winternl.h> |
michael@0 | 65 | #include "d3dkmtQueryStatistics.h" |
michael@0 | 66 | |
michael@0 | 67 | #include "SurfaceCache.h" |
michael@0 | 68 | #include "gfxPrefs.h" |
michael@0 | 69 | |
michael@0 | 70 | using namespace mozilla; |
michael@0 | 71 | using namespace mozilla::gfx; |
michael@0 | 72 | using namespace mozilla::layers; |
michael@0 | 73 | using namespace mozilla::widget; |
michael@0 | 74 | using namespace mozilla::image; |
michael@0 | 75 | |
michael@0 | 76 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 77 | |
michael@0 | 78 | static const char *kFeatureLevelPref = |
michael@0 | 79 | "gfx.direct3d.last_used_feature_level_idx"; |
michael@0 | 80 | static const int kSupportedFeatureLevels[] = |
michael@0 | 81 | { D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0, |
michael@0 | 82 | D3D10_FEATURE_LEVEL_9_3 }; |
michael@0 | 83 | |
michael@0 | 84 | class GfxD2DSurfaceReporter MOZ_FINAL : public nsIMemoryReporter |
michael@0 | 85 | { |
michael@0 | 86 | public: |
michael@0 | 87 | NS_DECL_ISUPPORTS |
michael@0 | 88 | |
michael@0 | 89 | NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, |
michael@0 | 90 | nsISupports* aData) |
michael@0 | 91 | { |
michael@0 | 92 | nsresult rv; |
michael@0 | 93 | |
michael@0 | 94 | int64_t amount = cairo_d2d_get_image_surface_cache_usage(); |
michael@0 | 95 | rv = MOZ_COLLECT_REPORT( |
michael@0 | 96 | "gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount, |
michael@0 | 97 | "Memory used by the Direct2D internal surface cache."); |
michael@0 | 98 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 99 | |
michael@0 | 100 | cairo_device_t *device = |
michael@0 | 101 | gfxWindowsPlatform::GetPlatform()->GetD2DDevice(); |
michael@0 | 102 | amount = device ? cairo_d2d_get_surface_vram_usage(device) : 0; |
michael@0 | 103 | rv = MOZ_COLLECT_REPORT( |
michael@0 | 104 | "gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES, amount, |
michael@0 | 105 | "Video memory used by D2D surfaces."); |
michael@0 | 106 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 107 | |
michael@0 | 108 | return NS_OK; |
michael@0 | 109 | } |
michael@0 | 110 | }; |
michael@0 | 111 | |
michael@0 | 112 | NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter) |
michael@0 | 113 | |
michael@0 | 114 | #endif |
michael@0 | 115 | |
michael@0 | 116 | class GfxD2DVramReporter MOZ_FINAL : public nsIMemoryReporter |
michael@0 | 117 | { |
michael@0 | 118 | public: |
michael@0 | 119 | NS_DECL_ISUPPORTS |
michael@0 | 120 | |
michael@0 | 121 | NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, |
michael@0 | 122 | nsISupports* aData) |
michael@0 | 123 | { |
michael@0 | 124 | nsresult rv; |
michael@0 | 125 | |
michael@0 | 126 | rv = MOZ_COLLECT_REPORT( |
michael@0 | 127 | "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES, |
michael@0 | 128 | Factory::GetD2DVRAMUsageDrawTarget(), |
michael@0 | 129 | "Video memory used by D2D DrawTargets."); |
michael@0 | 130 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 131 | |
michael@0 | 132 | rv = MOZ_COLLECT_REPORT( |
michael@0 | 133 | "gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES, |
michael@0 | 134 | Factory::GetD2DVRAMUsageSourceSurface(), |
michael@0 | 135 | "Video memory used by D2D SourceSurfaces."); |
michael@0 | 136 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 137 | |
michael@0 | 138 | return NS_OK; |
michael@0 | 139 | } |
michael@0 | 140 | }; |
michael@0 | 141 | |
michael@0 | 142 | NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter) |
michael@0 | 143 | |
michael@0 | 144 | #define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content" |
michael@0 | 145 | #define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts" |
michael@0 | 146 | |
michael@0 | 147 | #define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params." |
michael@0 | 148 | #define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma" |
michael@0 | 149 | #define GFX_CLEARTYPE_PARAMS_CONTRAST "gfx.font_rendering.cleartype_params.enhanced_contrast" |
michael@0 | 150 | #define GFX_CLEARTYPE_PARAMS_LEVEL "gfx.font_rendering.cleartype_params.cleartype_level" |
michael@0 | 151 | #define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure" |
michael@0 | 152 | #define GFX_CLEARTYPE_PARAMS_MODE "gfx.font_rendering.cleartype_params.rendering_mode" |
michael@0 | 153 | |
michael@0 | 154 | class GPUAdapterReporter : public nsIMemoryReporter |
michael@0 | 155 | { |
michael@0 | 156 | // Callers must Release the DXGIAdapter after use or risk mem-leak |
michael@0 | 157 | static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter) |
michael@0 | 158 | { |
michael@0 | 159 | ID3D10Device1 *D2D10Device; |
michael@0 | 160 | IDXGIDevice *DXGIDevice; |
michael@0 | 161 | bool result = false; |
michael@0 | 162 | |
michael@0 | 163 | if (D2D10Device = mozilla::gfx::Factory::GetDirect3D10Device()) { |
michael@0 | 164 | if (D2D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&DXGIDevice) == S_OK) { |
michael@0 | 165 | result = (DXGIDevice->GetAdapter(DXGIAdapter) == S_OK); |
michael@0 | 166 | DXGIDevice->Release(); |
michael@0 | 167 | } |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | return result; |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | public: |
michael@0 | 174 | NS_DECL_ISUPPORTS |
michael@0 | 175 | |
michael@0 | 176 | NS_IMETHOD |
michael@0 | 177 | CollectReports(nsIMemoryReporterCallback* aCb, |
michael@0 | 178 | nsISupports* aClosure) |
michael@0 | 179 | { |
michael@0 | 180 | HANDLE ProcessHandle = GetCurrentProcess(); |
michael@0 | 181 | |
michael@0 | 182 | int64_t dedicatedBytesUsed = 0; |
michael@0 | 183 | int64_t sharedBytesUsed = 0; |
michael@0 | 184 | int64_t committedBytesUsed = 0; |
michael@0 | 185 | IDXGIAdapter *DXGIAdapter; |
michael@0 | 186 | |
michael@0 | 187 | HMODULE gdi32Handle; |
michael@0 | 188 | PFND3DKMTQS queryD3DKMTStatistics; |
michael@0 | 189 | |
michael@0 | 190 | // GPU memory reporting is not available before Windows 7 |
michael@0 | 191 | if (!IsWin7OrLater()) |
michael@0 | 192 | return NS_OK; |
michael@0 | 193 | |
michael@0 | 194 | if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))) |
michael@0 | 195 | queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics"); |
michael@0 | 196 | |
michael@0 | 197 | if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) { |
michael@0 | 198 | // Most of this block is understood thanks to wj32's work on Process Hacker |
michael@0 | 199 | |
michael@0 | 200 | DXGI_ADAPTER_DESC adapterDesc; |
michael@0 | 201 | D3DKMTQS queryStatistics; |
michael@0 | 202 | |
michael@0 | 203 | DXGIAdapter->GetDesc(&adapterDesc); |
michael@0 | 204 | DXGIAdapter->Release(); |
michael@0 | 205 | |
michael@0 | 206 | memset(&queryStatistics, 0, sizeof(D3DKMTQS)); |
michael@0 | 207 | queryStatistics.Type = D3DKMTQS_PROCESS; |
michael@0 | 208 | queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; |
michael@0 | 209 | queryStatistics.hProcess = ProcessHandle; |
michael@0 | 210 | if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { |
michael@0 | 211 | committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated; |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | memset(&queryStatistics, 0, sizeof(D3DKMTQS)); |
michael@0 | 215 | queryStatistics.Type = D3DKMTQS_ADAPTER; |
michael@0 | 216 | queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; |
michael@0 | 217 | if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { |
michael@0 | 218 | ULONG i; |
michael@0 | 219 | ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments; |
michael@0 | 220 | |
michael@0 | 221 | for (i = 0; i < segmentCount; i++) { |
michael@0 | 222 | memset(&queryStatistics, 0, sizeof(D3DKMTQS)); |
michael@0 | 223 | queryStatistics.Type = D3DKMTQS_SEGMENT; |
michael@0 | 224 | queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; |
michael@0 | 225 | queryStatistics.QuerySegment.SegmentId = i; |
michael@0 | 226 | |
michael@0 | 227 | if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { |
michael@0 | 228 | bool aperture; |
michael@0 | 229 | |
michael@0 | 230 | // SegmentInformation has a different definition in Win7 than later versions |
michael@0 | 231 | if (!IsWin8OrLater()) |
michael@0 | 232 | aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture; |
michael@0 | 233 | else |
michael@0 | 234 | aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture; |
michael@0 | 235 | |
michael@0 | 236 | memset(&queryStatistics, 0, sizeof(D3DKMTQS)); |
michael@0 | 237 | queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT; |
michael@0 | 238 | queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; |
michael@0 | 239 | queryStatistics.hProcess = ProcessHandle; |
michael@0 | 240 | queryStatistics.QueryProcessSegment.SegmentId = i; |
michael@0 | 241 | if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { |
michael@0 | 242 | ULONGLONG bytesCommitted; |
michael@0 | 243 | if (!IsWin8OrLater()) |
michael@0 | 244 | bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win7.BytesCommitted; |
michael@0 | 245 | else |
michael@0 | 246 | bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win8.BytesCommitted; |
michael@0 | 247 | if (aperture) |
michael@0 | 248 | sharedBytesUsed += bytesCommitted; |
michael@0 | 249 | else |
michael@0 | 250 | dedicatedBytesUsed += bytesCommitted; |
michael@0 | 251 | } |
michael@0 | 252 | } |
michael@0 | 253 | } |
michael@0 | 254 | } |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | FreeLibrary(gdi32Handle); |
michael@0 | 258 | |
michael@0 | 259 | #define REPORT(_path, _amount, _desc) \ |
michael@0 | 260 | do { \ |
michael@0 | 261 | nsresult rv; \ |
michael@0 | 262 | rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ |
michael@0 | 263 | KIND_OTHER, UNITS_BYTES, _amount, \ |
michael@0 | 264 | NS_LITERAL_CSTRING(_desc), aClosure); \ |
michael@0 | 265 | NS_ENSURE_SUCCESS(rv, rv); \ |
michael@0 | 266 | } while (0) |
michael@0 | 267 | |
michael@0 | 268 | REPORT("gpu-committed", committedBytesUsed, |
michael@0 | 269 | "Memory committed by the Windows graphics system."); |
michael@0 | 270 | |
michael@0 | 271 | REPORT("gpu-dedicated", dedicatedBytesUsed, |
michael@0 | 272 | "Out-of-process memory allocated for this process in a " |
michael@0 | 273 | "physical GPU adapter's memory."); |
michael@0 | 274 | |
michael@0 | 275 | REPORT("gpu-shared", sharedBytesUsed, |
michael@0 | 276 | "In-process memory that is shared with the GPU."); |
michael@0 | 277 | |
michael@0 | 278 | #undef REPORT |
michael@0 | 279 | |
michael@0 | 280 | return NS_OK; |
michael@0 | 281 | } |
michael@0 | 282 | }; |
michael@0 | 283 | |
michael@0 | 284 | NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter) |
michael@0 | 285 | |
michael@0 | 286 | static __inline void |
michael@0 | 287 | BuildKeyNameFromFontName(nsAString &aName) |
michael@0 | 288 | { |
michael@0 | 289 | if (aName.Length() >= LF_FACESIZE) |
michael@0 | 290 | aName.Truncate(LF_FACESIZE - 1); |
michael@0 | 291 | ToLowerCase(aName); |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | gfxWindowsPlatform::gfxWindowsPlatform() |
michael@0 | 295 | : mD3D11DeviceInitialized(false) |
michael@0 | 296 | , mPrefFonts(50) |
michael@0 | 297 | { |
michael@0 | 298 | mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; |
michael@0 | 299 | mUseClearTypeAlways = UNINITIALIZED_VALUE; |
michael@0 | 300 | |
michael@0 | 301 | mUsingGDIFonts = false; |
michael@0 | 302 | |
michael@0 | 303 | /* |
michael@0 | 304 | * Initialize COM |
michael@0 | 305 | */ |
michael@0 | 306 | CoInitialize(nullptr); |
michael@0 | 307 | |
michael@0 | 308 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 309 | RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter()); |
michael@0 | 310 | mD2DDevice = nullptr; |
michael@0 | 311 | #endif |
michael@0 | 312 | RegisterStrongMemoryReporter(new GfxD2DVramReporter()); |
michael@0 | 313 | |
michael@0 | 314 | UpdateRenderMode(); |
michael@0 | 315 | |
michael@0 | 316 | RegisterStrongMemoryReporter(new GPUAdapterReporter()); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | gfxWindowsPlatform::~gfxWindowsPlatform() |
michael@0 | 320 | { |
michael@0 | 321 | mDeviceManager = nullptr; |
michael@0 | 322 | |
michael@0 | 323 | // not calling FT_Done_FreeType because cairo may still hold references to |
michael@0 | 324 | // these FT_Faces. See bug 458169. |
michael@0 | 325 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 326 | if (mD2DDevice) { |
michael@0 | 327 | cairo_release_device(mD2DDevice); |
michael@0 | 328 | } |
michael@0 | 329 | #endif |
michael@0 | 330 | |
michael@0 | 331 | mozilla::gfx::Factory::D2DCleanup(); |
michael@0 | 332 | |
michael@0 | 333 | /* |
michael@0 | 334 | * Uninitialize COM |
michael@0 | 335 | */ |
michael@0 | 336 | CoUninitialize(); |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | double |
michael@0 | 340 | gfxWindowsPlatform::GetDPIScale() |
michael@0 | 341 | { |
michael@0 | 342 | return WinUtils::LogToPhysFactor(); |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | void |
michael@0 | 346 | gfxWindowsPlatform::UpdateRenderMode() |
michael@0 | 347 | { |
michael@0 | 348 | /* Pick the default render mode for |
michael@0 | 349 | * desktop. |
michael@0 | 350 | */ |
michael@0 | 351 | mRenderMode = RENDER_GDI; |
michael@0 | 352 | |
michael@0 | 353 | bool isVistaOrHigher = IsVistaOrLater(); |
michael@0 | 354 | |
michael@0 | 355 | bool safeMode = false; |
michael@0 | 356 | nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1"); |
michael@0 | 357 | if (xr) |
michael@0 | 358 | xr->GetInSafeMode(&safeMode); |
michael@0 | 359 | |
michael@0 | 360 | mUseDirectWrite = Preferences::GetBool("gfx.font_rendering.directwrite.enabled", false); |
michael@0 | 361 | |
michael@0 | 362 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 363 | bool d2dDisabled = false; |
michael@0 | 364 | bool d2dForceEnabled = false; |
michael@0 | 365 | bool d2dBlocked = false; |
michael@0 | 366 | |
michael@0 | 367 | nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); |
michael@0 | 368 | if (gfxInfo) { |
michael@0 | 369 | int32_t status; |
michael@0 | 370 | if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) { |
michael@0 | 371 | if (status != nsIGfxInfo::FEATURE_NO_INFO) { |
michael@0 | 372 | d2dBlocked = true; |
michael@0 | 373 | } |
michael@0 | 374 | } |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | // These will only be evaluated once, and any subsequent changes to |
michael@0 | 378 | // the preferences will be ignored until restart. |
michael@0 | 379 | d2dDisabled = gfxPrefs::Direct2DDisabled(); |
michael@0 | 380 | d2dForceEnabled = gfxPrefs::Direct2DForceEnabled(); |
michael@0 | 381 | |
michael@0 | 382 | bool tryD2D = d2dForceEnabled || (!d2dBlocked && !gfxPrefs::LayersPreferD3D9()); |
michael@0 | 383 | |
michael@0 | 384 | // Do not ever try if d2d is explicitly disabled, |
michael@0 | 385 | // or if we're not using DWrite fonts. |
michael@0 | 386 | if (d2dDisabled || mUsingGDIFonts) { |
michael@0 | 387 | tryD2D = false; |
michael@0 | 388 | } |
michael@0 | 389 | |
michael@0 | 390 | if (isVistaOrHigher && !safeMode && tryD2D) { |
michael@0 | 391 | VerifyD2DDevice(d2dForceEnabled); |
michael@0 | 392 | if (mD2DDevice) { |
michael@0 | 393 | mRenderMode = RENDER_DIRECT2D; |
michael@0 | 394 | mUseDirectWrite = true; |
michael@0 | 395 | } |
michael@0 | 396 | } else { |
michael@0 | 397 | mD2DDevice = nullptr; |
michael@0 | 398 | } |
michael@0 | 399 | #endif |
michael@0 | 400 | |
michael@0 | 401 | #ifdef CAIRO_HAS_DWRITE_FONT |
michael@0 | 402 | // Enable when it's preffed on -and- we're using Vista or higher. Or when |
michael@0 | 403 | // we're going to use D2D. |
michael@0 | 404 | if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) { |
michael@0 | 405 | mozilla::ScopedGfxFeatureReporter reporter("DWrite"); |
michael@0 | 406 | decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) |
michael@0 | 407 | GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"); |
michael@0 | 408 | |
michael@0 | 409 | if (createDWriteFactory) { |
michael@0 | 410 | /** |
michael@0 | 411 | * I need a direct pointer to be able to cast to IUnknown**, I also |
michael@0 | 412 | * need to remember to release this because the nsRefPtr will |
michael@0 | 413 | * AddRef it. |
michael@0 | 414 | */ |
michael@0 | 415 | IDWriteFactory *factory; |
michael@0 | 416 | HRESULT hr = createDWriteFactory( |
michael@0 | 417 | DWRITE_FACTORY_TYPE_SHARED, |
michael@0 | 418 | __uuidof(IDWriteFactory), |
michael@0 | 419 | reinterpret_cast<IUnknown**>(&factory)); |
michael@0 | 420 | |
michael@0 | 421 | if (SUCCEEDED(hr) && factory) { |
michael@0 | 422 | mDWriteFactory = factory; |
michael@0 | 423 | factory->Release(); |
michael@0 | 424 | hr = mDWriteFactory->CreateTextAnalyzer( |
michael@0 | 425 | getter_AddRefs(mDWriteAnalyzer)); |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | SetupClearTypeParams(); |
michael@0 | 429 | |
michael@0 | 430 | if (hr == S_OK) |
michael@0 | 431 | reporter.SetSuccessful(); |
michael@0 | 432 | } |
michael@0 | 433 | } |
michael@0 | 434 | #endif |
michael@0 | 435 | |
michael@0 | 436 | uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); |
michael@0 | 437 | uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); |
michael@0 | 438 | BackendType defaultBackend = BackendType::CAIRO; |
michael@0 | 439 | if (mRenderMode == RENDER_DIRECT2D) { |
michael@0 | 440 | canvasMask |= BackendTypeBit(BackendType::DIRECT2D); |
michael@0 | 441 | contentMask |= BackendTypeBit(BackendType::DIRECT2D); |
michael@0 | 442 | defaultBackend = BackendType::DIRECT2D; |
michael@0 | 443 | } else { |
michael@0 | 444 | canvasMask |= BackendTypeBit(BackendType::SKIA); |
michael@0 | 445 | } |
michael@0 | 446 | contentMask |= BackendTypeBit(BackendType::SKIA); |
michael@0 | 447 | InitBackendPrefs(canvasMask, defaultBackend, |
michael@0 | 448 | contentMask, defaultBackend); |
michael@0 | 449 | } |
michael@0 | 450 | |
michael@0 | 451 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 452 | HRESULT |
michael@0 | 453 | gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1, |
michael@0 | 454 | int featureLevelIndex) |
michael@0 | 455 | { |
michael@0 | 456 | nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll")); |
michael@0 | 457 | if (!d3d10module) |
michael@0 | 458 | return E_FAIL; |
michael@0 | 459 | decltype(D3D10CreateDevice1)* createD3DDevice = |
michael@0 | 460 | (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1"); |
michael@0 | 461 | if (!createD3DDevice) |
michael@0 | 462 | return E_FAIL; |
michael@0 | 463 | |
michael@0 | 464 | nsRefPtr<ID3D10Device1> device; |
michael@0 | 465 | HRESULT hr = |
michael@0 | 466 | createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr, |
michael@0 | 467 | D3D10_CREATE_DEVICE_BGRA_SUPPORT | |
michael@0 | 468 | D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, |
michael@0 | 469 | static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]), |
michael@0 | 470 | D3D10_1_SDK_VERSION, getter_AddRefs(device)); |
michael@0 | 471 | |
michael@0 | 472 | // If we fail here, the DirectX version or video card probably |
michael@0 | 473 | // changed. We previously could use 10.1 but now we can't |
michael@0 | 474 | // anymore. Revert back to doing a 10.0 check first before |
michael@0 | 475 | // the 10.1 check. |
michael@0 | 476 | if (device) { |
michael@0 | 477 | mD2DDevice = cairo_d2d_create_device_from_d3d10device(device); |
michael@0 | 478 | |
michael@0 | 479 | // Setup a pref for future launch optimizaitons when in main process. |
michael@0 | 480 | if (XRE_GetProcessType() == GeckoProcessType_Default) { |
michael@0 | 481 | Preferences::SetInt(kFeatureLevelPref, featureLevelIndex); |
michael@0 | 482 | } |
michael@0 | 483 | } |
michael@0 | 484 | |
michael@0 | 485 | return device ? S_OK : hr; |
michael@0 | 486 | } |
michael@0 | 487 | #endif |
michael@0 | 488 | |
michael@0 | 489 | void |
michael@0 | 490 | gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) |
michael@0 | 491 | { |
michael@0 | 492 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 493 | if (mD2DDevice) { |
michael@0 | 494 | ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice); |
michael@0 | 495 | |
michael@0 | 496 | if (SUCCEEDED(device->GetDeviceRemovedReason())) { |
michael@0 | 497 | return; |
michael@0 | 498 | } |
michael@0 | 499 | mD2DDevice = nullptr; |
michael@0 | 500 | |
michael@0 | 501 | // Surface cache needs to be invalidated since it may contain vector |
michael@0 | 502 | // images rendered with our old, broken D2D device. |
michael@0 | 503 | SurfaceCache::DiscardAll(); |
michael@0 | 504 | } |
michael@0 | 505 | |
michael@0 | 506 | mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce); |
michael@0 | 507 | |
michael@0 | 508 | nsRefPtr<ID3D10Device1> device; |
michael@0 | 509 | |
michael@0 | 510 | int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels); |
michael@0 | 511 | // If we're not running in Metro don't allow DX9.3 |
michael@0 | 512 | if (!IsRunningInWindowsMetro()) { |
michael@0 | 513 | supportedFeatureLevelsCount--; |
michael@0 | 514 | } |
michael@0 | 515 | |
michael@0 | 516 | nsRefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter(); |
michael@0 | 517 | |
michael@0 | 518 | if (!adapter1) { |
michael@0 | 519 | // Unable to create adapter, abort acceleration. |
michael@0 | 520 | return; |
michael@0 | 521 | } |
michael@0 | 522 | |
michael@0 | 523 | // It takes a lot of time (5-10% of startup time or ~100ms) to do both |
michael@0 | 524 | // a createD3DDevice on D3D10_FEATURE_LEVEL_10_0. We therefore store |
michael@0 | 525 | // the last used feature level to go direct to that. |
michael@0 | 526 | int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0); |
michael@0 | 527 | if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0) |
michael@0 | 528 | featureLevelIndex = 0; |
michael@0 | 529 | |
michael@0 | 530 | // Start with the last used feature level, and move to lower DX versions |
michael@0 | 531 | // until we find one that works. |
michael@0 | 532 | HRESULT hr = E_FAIL; |
michael@0 | 533 | for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) { |
michael@0 | 534 | hr = CreateDevice(adapter1, i); |
michael@0 | 535 | // If it succeeded we found the first available feature level |
michael@0 | 536 | if (SUCCEEDED(hr)) |
michael@0 | 537 | break; |
michael@0 | 538 | } |
michael@0 | 539 | |
michael@0 | 540 | // If we succeeded in creating a device, try for a newer device |
michael@0 | 541 | // that we haven't tried yet. |
michael@0 | 542 | if (SUCCEEDED(hr)) { |
michael@0 | 543 | for (int i = featureLevelIndex - 1; i >= 0; i--) { |
michael@0 | 544 | hr = CreateDevice(adapter1, i); |
michael@0 | 545 | // If it failed then we don't have new hardware |
michael@0 | 546 | if (FAILED(hr)) { |
michael@0 | 547 | break; |
michael@0 | 548 | } |
michael@0 | 549 | } |
michael@0 | 550 | } |
michael@0 | 551 | |
michael@0 | 552 | if (!mD2DDevice && aAttemptForce) { |
michael@0 | 553 | mD2DDevice = cairo_d2d_create_device(); |
michael@0 | 554 | } |
michael@0 | 555 | |
michael@0 | 556 | if (mD2DDevice) { |
michael@0 | 557 | reporter.SetSuccessful(); |
michael@0 | 558 | mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice)); |
michael@0 | 559 | } |
michael@0 | 560 | #endif |
michael@0 | 561 | } |
michael@0 | 562 | |
michael@0 | 563 | gfxPlatformFontList* |
michael@0 | 564 | gfxWindowsPlatform::CreatePlatformFontList() |
michael@0 | 565 | { |
michael@0 | 566 | mUsingGDIFonts = false; |
michael@0 | 567 | gfxPlatformFontList *pfl; |
michael@0 | 568 | #ifdef CAIRO_HAS_DWRITE_FONT |
michael@0 | 569 | // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd |
michael@0 | 570 | // crashers so blacklist them altogether |
michael@0 | 571 | if (IsNotWin7PreRTM() && GetDWriteFactory()) { |
michael@0 | 572 | pfl = new gfxDWriteFontList(); |
michael@0 | 573 | if (NS_SUCCEEDED(pfl->InitFontList())) { |
michael@0 | 574 | return pfl; |
michael@0 | 575 | } |
michael@0 | 576 | // DWrite font initialization failed! Don't know why this would happen, |
michael@0 | 577 | // but apparently it can - see bug 594865. |
michael@0 | 578 | // So we're going to fall back to GDI fonts & rendering. |
michael@0 | 579 | gfxPlatformFontList::Shutdown(); |
michael@0 | 580 | SetRenderMode(RENDER_GDI); |
michael@0 | 581 | } |
michael@0 | 582 | #endif |
michael@0 | 583 | pfl = new gfxGDIFontList(); |
michael@0 | 584 | mUsingGDIFonts = true; |
michael@0 | 585 | |
michael@0 | 586 | if (NS_SUCCEEDED(pfl->InitFontList())) { |
michael@0 | 587 | return pfl; |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | gfxPlatformFontList::Shutdown(); |
michael@0 | 591 | return nullptr; |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | already_AddRefed<gfxASurface> |
michael@0 | 595 | gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& size, |
michael@0 | 596 | gfxContentType contentType) |
michael@0 | 597 | { |
michael@0 | 598 | nsRefPtr<gfxASurface> surf = nullptr; |
michael@0 | 599 | |
michael@0 | 600 | #ifdef CAIRO_HAS_WIN32_SURFACE |
michael@0 | 601 | if (mRenderMode == RENDER_GDI) |
michael@0 | 602 | surf = new gfxWindowsSurface(ThebesIntSize(size), |
michael@0 | 603 | OptimalFormatForContent(contentType)); |
michael@0 | 604 | #endif |
michael@0 | 605 | |
michael@0 | 606 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 607 | if (mRenderMode == RENDER_DIRECT2D) |
michael@0 | 608 | surf = new gfxD2DSurface(ThebesIntSize(size), |
michael@0 | 609 | OptimalFormatForContent(contentType)); |
michael@0 | 610 | #endif |
michael@0 | 611 | |
michael@0 | 612 | if (!surf || surf->CairoStatus()) { |
michael@0 | 613 | surf = new gfxImageSurface(ThebesIntSize(size), |
michael@0 | 614 | OptimalFormatForContent(contentType)); |
michael@0 | 615 | } |
michael@0 | 616 | |
michael@0 | 617 | return surf.forget(); |
michael@0 | 618 | } |
michael@0 | 619 | |
michael@0 | 620 | already_AddRefed<gfxASurface> |
michael@0 | 621 | gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize, |
michael@0 | 622 | gfxContentType aContentType) |
michael@0 | 623 | { |
michael@0 | 624 | #ifdef CAIRO_HAS_D2D_SURFACE |
michael@0 | 625 | if (mRenderMode == RENDER_DIRECT2D) { |
michael@0 | 626 | nsRefPtr<gfxASurface> surface = |
michael@0 | 627 | new gfxImageSurface(aSize, OptimalFormatForContent(aContentType)); |
michael@0 | 628 | return surface.forget(); |
michael@0 | 629 | } |
michael@0 | 630 | #endif |
michael@0 | 631 | |
michael@0 | 632 | nsRefPtr<gfxASurface> surface = CreateOffscreenSurface(aSize.ToIntSize(), |
michael@0 | 633 | aContentType); |
michael@0 | 634 | #ifdef DEBUG |
michael@0 | 635 | nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface(); |
michael@0 | 636 | NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface"); |
michael@0 | 637 | #endif |
michael@0 | 638 | return surface.forget(); |
michael@0 | 639 | } |
michael@0 | 640 | |
michael@0 | 641 | TemporaryRef<ScaledFont> |
michael@0 | 642 | gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) |
michael@0 | 643 | { |
michael@0 | 644 | if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) { |
michael@0 | 645 | gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont); |
michael@0 | 646 | |
michael@0 | 647 | NativeFont nativeFont; |
michael@0 | 648 | nativeFont.mType = NativeFontType::DWRITE_FONT_FACE; |
michael@0 | 649 | nativeFont.mFont = font->GetFontFace(); |
michael@0 | 650 | |
michael@0 | 651 | if (aTarget->GetType() == BackendType::CAIRO) { |
michael@0 | 652 | return Factory::CreateScaledFontWithCairo(nativeFont, |
michael@0 | 653 | font->GetAdjustedSize(), |
michael@0 | 654 | font->GetCairoScaledFont()); |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | return Factory::CreateScaledFontForNativeFont(nativeFont, |
michael@0 | 658 | font->GetAdjustedSize()); |
michael@0 | 659 | } |
michael@0 | 660 | |
michael@0 | 661 | NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI, |
michael@0 | 662 | "Fonts on windows should be GDI or DWrite!"); |
michael@0 | 663 | |
michael@0 | 664 | NativeFont nativeFont; |
michael@0 | 665 | nativeFont.mType = NativeFontType::GDI_FONT_FACE; |
michael@0 | 666 | LOGFONT lf; |
michael@0 | 667 | GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf); |
michael@0 | 668 | nativeFont.mFont = &lf; |
michael@0 | 669 | |
michael@0 | 670 | if (aTarget->GetType() == BackendType::CAIRO) { |
michael@0 | 671 | return Factory::CreateScaledFontWithCairo(nativeFont, |
michael@0 | 672 | aFont->GetAdjustedSize(), |
michael@0 | 673 | aFont->GetCairoScaledFont()); |
michael@0 | 674 | } |
michael@0 | 675 | |
michael@0 | 676 | return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | already_AddRefed<gfxASurface> |
michael@0 | 680 | gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) |
michael@0 | 681 | { |
michael@0 | 682 | #ifdef XP_WIN |
michael@0 | 683 | if (aTarget->GetType() == BackendType::DIRECT2D) { |
michael@0 | 684 | if (!GetD2DDevice()) { |
michael@0 | 685 | // We no longer have a D2D device, can't do this. |
michael@0 | 686 | return nullptr; |
michael@0 | 687 | } |
michael@0 | 688 | |
michael@0 | 689 | RefPtr<ID3D10Texture2D> texture = |
michael@0 | 690 | static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NativeSurfaceType::D3D10_TEXTURE)); |
michael@0 | 691 | |
michael@0 | 692 | if (!texture) { |
michael@0 | 693 | return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); |
michael@0 | 694 | } |
michael@0 | 695 | |
michael@0 | 696 | aTarget->Flush(); |
michael@0 | 697 | |
michael@0 | 698 | nsRefPtr<gfxASurface> surf = |
michael@0 | 699 | new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); |
michael@0 | 700 | |
michael@0 | 701 | // shouldn't this hold a reference? |
michael@0 | 702 | surf->SetData(&kDrawTarget, aTarget, nullptr); |
michael@0 | 703 | return surf.forget(); |
michael@0 | 704 | } |
michael@0 | 705 | #endif |
michael@0 | 706 | |
michael@0 | 707 | return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); |
michael@0 | 708 | } |
michael@0 | 709 | |
michael@0 | 710 | nsresult |
michael@0 | 711 | gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup, |
michael@0 | 712 | const nsACString& aGenericFamily, |
michael@0 | 713 | nsTArray<nsString>& aListOfFonts) |
michael@0 | 714 | { |
michael@0 | 715 | gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts); |
michael@0 | 716 | |
michael@0 | 717 | return NS_OK; |
michael@0 | 718 | } |
michael@0 | 719 | |
michael@0 | 720 | static void |
michael@0 | 721 | RemoveCharsetFromFontSubstitute(nsAString &aName) |
michael@0 | 722 | { |
michael@0 | 723 | int32_t comma = aName.FindChar(char16_t(',')); |
michael@0 | 724 | if (comma >= 0) |
michael@0 | 725 | aName.Truncate(comma); |
michael@0 | 726 | } |
michael@0 | 727 | |
michael@0 | 728 | nsresult |
michael@0 | 729 | gfxWindowsPlatform::UpdateFontList() |
michael@0 | 730 | { |
michael@0 | 731 | gfxPlatformFontList::PlatformFontList()->UpdateFontList(); |
michael@0 | 732 | |
michael@0 | 733 | return NS_OK; |
michael@0 | 734 | } |
michael@0 | 735 | |
michael@0 | 736 | static const char kFontAparajita[] = "Aparajita"; |
michael@0 | 737 | static const char kFontArabicTypesetting[] = "Arabic Typesetting"; |
michael@0 | 738 | static const char kFontArial[] = "Arial"; |
michael@0 | 739 | static const char kFontArialUnicodeMS[] = "Arial Unicode MS"; |
michael@0 | 740 | static const char kFontCambria[] = "Cambria"; |
michael@0 | 741 | static const char kFontCambriaMath[] = "Cambria Math"; |
michael@0 | 742 | static const char kFontEbrima[] = "Ebrima"; |
michael@0 | 743 | static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa"; |
michael@0 | 744 | static const char kFontEuphemia[] = "Euphemia"; |
michael@0 | 745 | static const char kFontGabriola[] = "Gabriola"; |
michael@0 | 746 | static const char kFontJavaneseText[] = "Javanese Text"; |
michael@0 | 747 | static const char kFontKhmerUI[] = "Khmer UI"; |
michael@0 | 748 | static const char kFontLaoUI[] = "Lao UI"; |
michael@0 | 749 | static const char kFontLeelawadeeUI[] = "Leelawadee UI"; |
michael@0 | 750 | static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode"; |
michael@0 | 751 | static const char kFontMVBoli[] = "MV Boli"; |
michael@0 | 752 | static const char kFontMalgunGothic[] = "Malgun Gothic"; |
michael@0 | 753 | static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei"; |
michael@0 | 754 | static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue"; |
michael@0 | 755 | static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa"; |
michael@0 | 756 | static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le"; |
michael@0 | 757 | static const char kFontMicrosoftUighur[] = "Microsoft Uighur"; |
michael@0 | 758 | static const char kFontMicrosoftYaHei[] = "Microsoft YaHei"; |
michael@0 | 759 | static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti"; |
michael@0 | 760 | static const char kFontMeiryo[] = "Meiryo"; |
michael@0 | 761 | static const char kFontMongolianBaiti[] = "Mongolian Baiti"; |
michael@0 | 762 | static const char kFontMyanmarText[] = "Myanmar Text"; |
michael@0 | 763 | static const char kFontNirmalaUI[] = "Nirmala UI"; |
michael@0 | 764 | static const char kFontNyala[] = "Nyala"; |
michael@0 | 765 | static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee"; |
michael@0 | 766 | static const char kFontSegoeUI[] = "Segoe UI"; |
michael@0 | 767 | static const char kFontSegoeUISymbol[] = "Segoe UI Symbol"; |
michael@0 | 768 | static const char kFontSylfaen[] = "Sylfaen"; |
michael@0 | 769 | static const char kFontTraditionalArabic[] = "Traditional Arabic"; |
michael@0 | 770 | static const char kFontUtsaah[] = "Utsaah"; |
michael@0 | 771 | static const char kFontYuGothic[] = "Yu Gothic"; |
michael@0 | 772 | |
michael@0 | 773 | void |
michael@0 | 774 | gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh, |
michael@0 | 775 | int32_t aRunScript, |
michael@0 | 776 | nsTArray<const char*>& aFontList) |
michael@0 | 777 | { |
michael@0 | 778 | // Arial is used as the default fallback for system fallback |
michael@0 | 779 | aFontList.AppendElement(kFontArial); |
michael@0 | 780 | |
michael@0 | 781 | if (!IS_IN_BMP(aCh)) { |
michael@0 | 782 | uint32_t p = aCh >> 16; |
michael@0 | 783 | if (p == 1) { // SMP plane |
michael@0 | 784 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 785 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 786 | aFontList.AppendElement(kFontNirmalaUI); |
michael@0 | 787 | aFontList.AppendElement(kFontCambriaMath); |
michael@0 | 788 | } |
michael@0 | 789 | } else { |
michael@0 | 790 | uint32_t b = (aCh >> 8) & 0xff; |
michael@0 | 791 | |
michael@0 | 792 | switch (b) { |
michael@0 | 793 | case 0x05: |
michael@0 | 794 | aFontList.AppendElement(kFontEstrangeloEdessa); |
michael@0 | 795 | aFontList.AppendElement(kFontCambria); |
michael@0 | 796 | break; |
michael@0 | 797 | case 0x06: |
michael@0 | 798 | aFontList.AppendElement(kFontMicrosoftUighur); |
michael@0 | 799 | break; |
michael@0 | 800 | case 0x07: |
michael@0 | 801 | aFontList.AppendElement(kFontEstrangeloEdessa); |
michael@0 | 802 | aFontList.AppendElement(kFontMVBoli); |
michael@0 | 803 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 804 | break; |
michael@0 | 805 | case 0x09: |
michael@0 | 806 | aFontList.AppendElement(kFontNirmalaUI); |
michael@0 | 807 | aFontList.AppendElement(kFontUtsaah); |
michael@0 | 808 | aFontList.AppendElement(kFontAparajita); |
michael@0 | 809 | break; |
michael@0 | 810 | case 0x0e: |
michael@0 | 811 | aFontList.AppendElement(kFontLaoUI); |
michael@0 | 812 | break; |
michael@0 | 813 | case 0x10: |
michael@0 | 814 | aFontList.AppendElement(kFontMyanmarText); |
michael@0 | 815 | break; |
michael@0 | 816 | case 0x11: |
michael@0 | 817 | aFontList.AppendElement(kFontMalgunGothic); |
michael@0 | 818 | break; |
michael@0 | 819 | case 0x12: |
michael@0 | 820 | case 0x13: |
michael@0 | 821 | aFontList.AppendElement(kFontNyala); |
michael@0 | 822 | aFontList.AppendElement(kFontPlantagenetCherokee); |
michael@0 | 823 | break; |
michael@0 | 824 | case 0x14: |
michael@0 | 825 | case 0x15: |
michael@0 | 826 | case 0x16: |
michael@0 | 827 | aFontList.AppendElement(kFontEuphemia); |
michael@0 | 828 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 829 | break; |
michael@0 | 830 | case 0x17: |
michael@0 | 831 | aFontList.AppendElement(kFontKhmerUI); |
michael@0 | 832 | break; |
michael@0 | 833 | case 0x18: // Mongolian |
michael@0 | 834 | aFontList.AppendElement(kFontMongolianBaiti); |
michael@0 | 835 | aFontList.AppendElement(kFontEuphemia); |
michael@0 | 836 | break; |
michael@0 | 837 | case 0x19: |
michael@0 | 838 | aFontList.AppendElement(kFontMicrosoftTaiLe); |
michael@0 | 839 | aFontList.AppendElement(kFontMicrosoftNewTaiLue); |
michael@0 | 840 | aFontList.AppendElement(kFontKhmerUI); |
michael@0 | 841 | break; |
michael@0 | 842 | break; |
michael@0 | 843 | case 0x1a: |
michael@0 | 844 | aFontList.AppendElement(kFontLeelawadeeUI); |
michael@0 | 845 | break; |
michael@0 | 846 | case 0x1c: |
michael@0 | 847 | aFontList.AppendElement(kFontNirmalaUI); |
michael@0 | 848 | break; |
michael@0 | 849 | case 0x20: // Symbol ranges |
michael@0 | 850 | case 0x21: |
michael@0 | 851 | case 0x22: |
michael@0 | 852 | case 0x23: |
michael@0 | 853 | case 0x24: |
michael@0 | 854 | case 0x25: |
michael@0 | 855 | case 0x26: |
michael@0 | 856 | case 0x27: |
michael@0 | 857 | case 0x29: |
michael@0 | 858 | case 0x2a: |
michael@0 | 859 | case 0x2b: |
michael@0 | 860 | case 0x2c: |
michael@0 | 861 | aFontList.AppendElement(kFontSegoeUI); |
michael@0 | 862 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 863 | aFontList.AppendElement(kFontCambria); |
michael@0 | 864 | aFontList.AppendElement(kFontMeiryo); |
michael@0 | 865 | aFontList.AppendElement(kFontArial); |
michael@0 | 866 | aFontList.AppendElement(kFontLucidaSansUnicode); |
michael@0 | 867 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 868 | break; |
michael@0 | 869 | case 0x2d: |
michael@0 | 870 | case 0x2e: |
michael@0 | 871 | case 0x2f: |
michael@0 | 872 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 873 | aFontList.AppendElement(kFontNyala); |
michael@0 | 874 | aFontList.AppendElement(kFontSegoeUI); |
michael@0 | 875 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 876 | aFontList.AppendElement(kFontMeiryo); |
michael@0 | 877 | break; |
michael@0 | 878 | case 0x28: // Braille |
michael@0 | 879 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 880 | break; |
michael@0 | 881 | case 0x30: |
michael@0 | 882 | case 0x31: |
michael@0 | 883 | aFontList.AppendElement(kFontMicrosoftYaHei); |
michael@0 | 884 | break; |
michael@0 | 885 | case 0x32: |
michael@0 | 886 | aFontList.AppendElement(kFontMalgunGothic); |
michael@0 | 887 | break; |
michael@0 | 888 | case 0x4d: |
michael@0 | 889 | aFontList.AppendElement(kFontSegoeUISymbol); |
michael@0 | 890 | break; |
michael@0 | 891 | case 0x9f: |
michael@0 | 892 | aFontList.AppendElement(kFontMicrosoftYaHei); |
michael@0 | 893 | aFontList.AppendElement(kFontYuGothic); |
michael@0 | 894 | break; |
michael@0 | 895 | case 0xa0: // Yi |
michael@0 | 896 | case 0xa1: |
michael@0 | 897 | case 0xa2: |
michael@0 | 898 | case 0xa3: |
michael@0 | 899 | case 0xa4: |
michael@0 | 900 | aFontList.AppendElement(kFontMicrosoftYiBaiti); |
michael@0 | 901 | aFontList.AppendElement(kFontSegoeUI); |
michael@0 | 902 | break; |
michael@0 | 903 | case 0xa5: |
michael@0 | 904 | case 0xa6: |
michael@0 | 905 | case 0xa7: |
michael@0 | 906 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 907 | aFontList.AppendElement(kFontSegoeUI); |
michael@0 | 908 | aFontList.AppendElement(kFontCambriaMath); |
michael@0 | 909 | break; |
michael@0 | 910 | case 0xa8: |
michael@0 | 911 | aFontList.AppendElement(kFontMicrosoftPhagsPa); |
michael@0 | 912 | aFontList.AppendElement(kFontNirmalaUI); |
michael@0 | 913 | break; |
michael@0 | 914 | case 0xa9: |
michael@0 | 915 | aFontList.AppendElement(kFontMalgunGothic); |
michael@0 | 916 | aFontList.AppendElement(kFontJavaneseText); |
michael@0 | 917 | break; |
michael@0 | 918 | case 0xaa: |
michael@0 | 919 | aFontList.AppendElement(kFontMyanmarText); |
michael@0 | 920 | break; |
michael@0 | 921 | case 0xab: |
michael@0 | 922 | aFontList.AppendElement(kFontEbrima); |
michael@0 | 923 | aFontList.AppendElement(kFontNyala); |
michael@0 | 924 | break; |
michael@0 | 925 | case 0xd7: |
michael@0 | 926 | aFontList.AppendElement(kFontMalgunGothic); |
michael@0 | 927 | break; |
michael@0 | 928 | case 0xfb: |
michael@0 | 929 | aFontList.AppendElement(kFontMicrosoftUighur); |
michael@0 | 930 | aFontList.AppendElement(kFontGabriola); |
michael@0 | 931 | aFontList.AppendElement(kFontSylfaen); |
michael@0 | 932 | break; |
michael@0 | 933 | case 0xfc: |
michael@0 | 934 | case 0xfd: |
michael@0 | 935 | aFontList.AppendElement(kFontTraditionalArabic); |
michael@0 | 936 | aFontList.AppendElement(kFontArabicTypesetting); |
michael@0 | 937 | break; |
michael@0 | 938 | case 0xfe: |
michael@0 | 939 | aFontList.AppendElement(kFontTraditionalArabic); |
michael@0 | 940 | aFontList.AppendElement(kFontMicrosoftJhengHei); |
michael@0 | 941 | break; |
michael@0 | 942 | case 0xff: |
michael@0 | 943 | aFontList.AppendElement(kFontMicrosoftJhengHei); |
michael@0 | 944 | break; |
michael@0 | 945 | default: |
michael@0 | 946 | break; |
michael@0 | 947 | } |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | // Arial Unicode MS has lots of glyphs for obscure characters, |
michael@0 | 951 | // use it as a last resort |
michael@0 | 952 | aFontList.AppendElement(kFontArialUnicodeMS); |
michael@0 | 953 | } |
michael@0 | 954 | |
michael@0 | 955 | struct ResolveData { |
michael@0 | 956 | ResolveData(gfxPlatform::FontResolverCallback aCallback, |
michael@0 | 957 | gfxWindowsPlatform *aCaller, const nsAString *aFontName, |
michael@0 | 958 | void *aClosure) : |
michael@0 | 959 | mFoundCount(0), mCallback(aCallback), mCaller(aCaller), |
michael@0 | 960 | mFontName(aFontName), mClosure(aClosure) {} |
michael@0 | 961 | uint32_t mFoundCount; |
michael@0 | 962 | gfxPlatform::FontResolverCallback mCallback; |
michael@0 | 963 | gfxWindowsPlatform *mCaller; |
michael@0 | 964 | const nsAString *mFontName; |
michael@0 | 965 | void *mClosure; |
michael@0 | 966 | }; |
michael@0 | 967 | |
michael@0 | 968 | nsresult |
michael@0 | 969 | gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName, |
michael@0 | 970 | FontResolverCallback aCallback, |
michael@0 | 971 | void *aClosure, |
michael@0 | 972 | bool& aAborted) |
michael@0 | 973 | { |
michael@0 | 974 | nsAutoString resolvedName; |
michael@0 | 975 | if (!gfxPlatformFontList::PlatformFontList()-> |
michael@0 | 976 | ResolveFontName(aFontName, resolvedName)) { |
michael@0 | 977 | aAborted = false; |
michael@0 | 978 | return NS_OK; |
michael@0 | 979 | } |
michael@0 | 980 | aAborted = !(*aCallback)(resolvedName, aClosure); |
michael@0 | 981 | return NS_OK; |
michael@0 | 982 | } |
michael@0 | 983 | |
michael@0 | 984 | nsresult |
michael@0 | 985 | gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) |
michael@0 | 986 | { |
michael@0 | 987 | gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName); |
michael@0 | 988 | return NS_OK; |
michael@0 | 989 | } |
michael@0 | 990 | |
michael@0 | 991 | gfxFontGroup * |
michael@0 | 992 | gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies, |
michael@0 | 993 | const gfxFontStyle *aStyle, |
michael@0 | 994 | gfxUserFontSet *aUserFontSet) |
michael@0 | 995 | { |
michael@0 | 996 | return new gfxFontGroup(aFamilies, aStyle, aUserFontSet); |
michael@0 | 997 | } |
michael@0 | 998 | |
michael@0 | 999 | gfxFontEntry* |
michael@0 | 1000 | gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, |
michael@0 | 1001 | const nsAString& aFontName) |
michael@0 | 1002 | { |
michael@0 | 1003 | return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry, |
michael@0 | 1004 | aFontName); |
michael@0 | 1005 | } |
michael@0 | 1006 | |
michael@0 | 1007 | gfxFontEntry* |
michael@0 | 1008 | gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, |
michael@0 | 1009 | const uint8_t *aFontData, uint32_t aLength) |
michael@0 | 1010 | { |
michael@0 | 1011 | return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry, |
michael@0 | 1012 | aFontData, |
michael@0 | 1013 | aLength); |
michael@0 | 1014 | } |
michael@0 | 1015 | |
michael@0 | 1016 | bool |
michael@0 | 1017 | gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) |
michael@0 | 1018 | { |
michael@0 | 1019 | // check for strange format flags |
michael@0 | 1020 | NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), |
michael@0 | 1021 | "strange font format hint set"); |
michael@0 | 1022 | |
michael@0 | 1023 | // accept supported formats |
michael@0 | 1024 | if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF | |
michael@0 | 1025 | gfxUserFontSet::FLAG_FORMAT_OPENTYPE | |
michael@0 | 1026 | gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) { |
michael@0 | 1027 | return true; |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | // reject all other formats, known and unknown |
michael@0 | 1031 | if (aFormatFlags != 0) { |
michael@0 | 1032 | return false; |
michael@0 | 1033 | } |
michael@0 | 1034 | |
michael@0 | 1035 | // no format hint set, need to look at data |
michael@0 | 1036 | return true; |
michael@0 | 1037 | } |
michael@0 | 1038 | |
michael@0 | 1039 | gfxFontFamily * |
michael@0 | 1040 | gfxWindowsPlatform::FindFontFamily(const nsAString& aName) |
michael@0 | 1041 | { |
michael@0 | 1042 | return gfxPlatformFontList::PlatformFontList()->FindFamily(aName); |
michael@0 | 1043 | } |
michael@0 | 1044 | |
michael@0 | 1045 | gfxFontEntry * |
michael@0 | 1046 | gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle) |
michael@0 | 1047 | { |
michael@0 | 1048 | nsRefPtr<gfxFontFamily> ff = FindFontFamily(aName); |
michael@0 | 1049 | if (!ff) |
michael@0 | 1050 | return nullptr; |
michael@0 | 1051 | |
michael@0 | 1052 | bool aNeedsBold; |
michael@0 | 1053 | return ff->FindFontForStyle(aFontStyle, aNeedsBold); |
michael@0 | 1054 | } |
michael@0 | 1055 | |
michael@0 | 1056 | void |
michael@0 | 1057 | gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size) |
michael@0 | 1058 | { |
michael@0 | 1059 | WCHAR str[MAX_PATH]; |
michael@0 | 1060 | DWORD size = MAX_PATH; |
michael@0 | 1061 | BOOL res; |
michael@0 | 1062 | |
michael@0 | 1063 | mem = nullptr; |
michael@0 | 1064 | mem_size = 0; |
michael@0 | 1065 | |
michael@0 | 1066 | HDC dc = GetDC(nullptr); |
michael@0 | 1067 | if (!dc) |
michael@0 | 1068 | return; |
michael@0 | 1069 | |
michael@0 | 1070 | #if _MSC_VER |
michael@0 | 1071 | __try { |
michael@0 | 1072 | res = GetICMProfileW(dc, &size, (LPWSTR)&str); |
michael@0 | 1073 | } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { |
michael@0 | 1074 | res = FALSE; |
michael@0 | 1075 | } |
michael@0 | 1076 | #else |
michael@0 | 1077 | res = GetICMProfileW(dc, &size, (LPWSTR)&str); |
michael@0 | 1078 | #endif |
michael@0 | 1079 | |
michael@0 | 1080 | ReleaseDC(nullptr, dc); |
michael@0 | 1081 | if (!res) |
michael@0 | 1082 | return; |
michael@0 | 1083 | |
michael@0 | 1084 | #ifdef _WIN32 |
michael@0 | 1085 | qcms_data_from_unicode_path(str, &mem, &mem_size); |
michael@0 | 1086 | |
michael@0 | 1087 | #ifdef DEBUG_tor |
michael@0 | 1088 | if (mem_size > 0) |
michael@0 | 1089 | fprintf(stderr, |
michael@0 | 1090 | "ICM profile read from %s successfully\n", |
michael@0 | 1091 | NS_ConvertUTF16toUTF8(str).get()); |
michael@0 | 1092 | #endif // DEBUG_tor |
michael@0 | 1093 | #endif // _WIN32 |
michael@0 | 1094 | } |
michael@0 | 1095 | |
michael@0 | 1096 | bool |
michael@0 | 1097 | gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array) |
michael@0 | 1098 | { |
michael@0 | 1099 | return mPrefFonts.Get(aKey, array); |
michael@0 | 1100 | } |
michael@0 | 1101 | |
michael@0 | 1102 | void |
michael@0 | 1103 | gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array) |
michael@0 | 1104 | { |
michael@0 | 1105 | mPrefFonts.Put(aKey, array); |
michael@0 | 1106 | } |
michael@0 | 1107 | |
michael@0 | 1108 | bool |
michael@0 | 1109 | gfxWindowsPlatform::UseClearTypeForDownloadableFonts() |
michael@0 | 1110 | { |
michael@0 | 1111 | if (mUseClearTypeForDownloadableFonts == UNINITIALIZED_VALUE) { |
michael@0 | 1112 | mUseClearTypeForDownloadableFonts = Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, true); |
michael@0 | 1113 | } |
michael@0 | 1114 | |
michael@0 | 1115 | return mUseClearTypeForDownloadableFonts; |
michael@0 | 1116 | } |
michael@0 | 1117 | |
michael@0 | 1118 | bool |
michael@0 | 1119 | gfxWindowsPlatform::UseClearTypeAlways() |
michael@0 | 1120 | { |
michael@0 | 1121 | if (mUseClearTypeAlways == UNINITIALIZED_VALUE) { |
michael@0 | 1122 | mUseClearTypeAlways = Preferences::GetBool(GFX_USE_CLEARTYPE_ALWAYS, false); |
michael@0 | 1123 | } |
michael@0 | 1124 | |
michael@0 | 1125 | return mUseClearTypeAlways; |
michael@0 | 1126 | } |
michael@0 | 1127 | |
michael@0 | 1128 | void |
michael@0 | 1129 | gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion) |
michael@0 | 1130 | { |
michael@0 | 1131 | DWORD versInfoSize, vers[4] = {0}; |
michael@0 | 1132 | // version info not available case |
michael@0 | 1133 | aVersion.Assign(NS_LITERAL_STRING("0.0.0.0")); |
michael@0 | 1134 | versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr); |
michael@0 | 1135 | nsAutoTArray<BYTE,512> versionInfo; |
michael@0 | 1136 | |
michael@0 | 1137 | if (versInfoSize == 0 || |
michael@0 | 1138 | !versionInfo.AppendElements(uint32_t(versInfoSize))) |
michael@0 | 1139 | { |
michael@0 | 1140 | return; |
michael@0 | 1141 | } |
michael@0 | 1142 | |
michael@0 | 1143 | if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize, |
michael@0 | 1144 | LPBYTE(versionInfo.Elements()))) |
michael@0 | 1145 | { |
michael@0 | 1146 | return; |
michael@0 | 1147 | } |
michael@0 | 1148 | |
michael@0 | 1149 | UINT len = 0; |
michael@0 | 1150 | VS_FIXEDFILEINFO *fileInfo = nullptr; |
michael@0 | 1151 | if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"), |
michael@0 | 1152 | (LPVOID *)&fileInfo, &len) || |
michael@0 | 1153 | len == 0 || |
michael@0 | 1154 | fileInfo == nullptr) |
michael@0 | 1155 | { |
michael@0 | 1156 | return; |
michael@0 | 1157 | } |
michael@0 | 1158 | |
michael@0 | 1159 | DWORD fileVersMS = fileInfo->dwFileVersionMS; |
michael@0 | 1160 | DWORD fileVersLS = fileInfo->dwFileVersionLS; |
michael@0 | 1161 | |
michael@0 | 1162 | vers[0] = HIWORD(fileVersMS); |
michael@0 | 1163 | vers[1] = LOWORD(fileVersMS); |
michael@0 | 1164 | vers[2] = HIWORD(fileVersLS); |
michael@0 | 1165 | vers[3] = LOWORD(fileVersLS); |
michael@0 | 1166 | |
michael@0 | 1167 | char buf[256]; |
michael@0 | 1168 | sprintf(buf, "%d.%d.%d.%d", vers[0], vers[1], vers[2], vers[3]); |
michael@0 | 1169 | aVersion.Assign(NS_ConvertUTF8toUTF16(buf)); |
michael@0 | 1170 | } |
michael@0 | 1171 | |
michael@0 | 1172 | void |
michael@0 | 1173 | gfxWindowsPlatform::GetCleartypeParams(nsTArray<ClearTypeParameterInfo>& aParams) |
michael@0 | 1174 | { |
michael@0 | 1175 | HKEY hKey, subKey; |
michael@0 | 1176 | DWORD i, rv, size, type; |
michael@0 | 1177 | WCHAR displayName[256], subkeyName[256]; |
michael@0 | 1178 | |
michael@0 | 1179 | aParams.Clear(); |
michael@0 | 1180 | |
michael@0 | 1181 | // construct subkeys based on HKLM subkeys, assume they are same for HKCU |
michael@0 | 1182 | rv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
michael@0 | 1183 | L"Software\\Microsoft\\Avalon.Graphics", |
michael@0 | 1184 | 0, KEY_READ, &hKey); |
michael@0 | 1185 | |
michael@0 | 1186 | if (rv != ERROR_SUCCESS) { |
michael@0 | 1187 | return; |
michael@0 | 1188 | } |
michael@0 | 1189 | |
michael@0 | 1190 | // enumerate over subkeys |
michael@0 | 1191 | for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) { |
michael@0 | 1192 | size = ArrayLength(displayName); |
michael@0 | 1193 | rv = RegEnumKeyExW(hKey, i, displayName, &size, |
michael@0 | 1194 | nullptr, nullptr, nullptr, nullptr); |
michael@0 | 1195 | if (rv != ERROR_SUCCESS) { |
michael@0 | 1196 | continue; |
michael@0 | 1197 | } |
michael@0 | 1198 | |
michael@0 | 1199 | ClearTypeParameterInfo ctinfo; |
michael@0 | 1200 | ctinfo.displayName.Assign(displayName); |
michael@0 | 1201 | |
michael@0 | 1202 | DWORD subrv, value; |
michael@0 | 1203 | bool foundData = false; |
michael@0 | 1204 | |
michael@0 | 1205 | swprintf_s(subkeyName, ArrayLength(subkeyName), |
michael@0 | 1206 | L"Software\\Microsoft\\Avalon.Graphics\\%s", displayName); |
michael@0 | 1207 | |
michael@0 | 1208 | // subkey for gamma, pixel structure |
michael@0 | 1209 | subrv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
michael@0 | 1210 | subkeyName, 0, KEY_QUERY_VALUE, &subKey); |
michael@0 | 1211 | |
michael@0 | 1212 | if (subrv == ERROR_SUCCESS) { |
michael@0 | 1213 | size = sizeof(value); |
michael@0 | 1214 | subrv = RegQueryValueExW(subKey, L"GammaLevel", nullptr, &type, |
michael@0 | 1215 | (LPBYTE)&value, &size); |
michael@0 | 1216 | if (subrv == ERROR_SUCCESS && type == REG_DWORD) { |
michael@0 | 1217 | foundData = true; |
michael@0 | 1218 | ctinfo.gamma = value; |
michael@0 | 1219 | } |
michael@0 | 1220 | |
michael@0 | 1221 | size = sizeof(value); |
michael@0 | 1222 | subrv = RegQueryValueExW(subKey, L"PixelStructure", nullptr, &type, |
michael@0 | 1223 | (LPBYTE)&value, &size); |
michael@0 | 1224 | if (subrv == ERROR_SUCCESS && type == REG_DWORD) { |
michael@0 | 1225 | foundData = true; |
michael@0 | 1226 | ctinfo.pixelStructure = value; |
michael@0 | 1227 | } |
michael@0 | 1228 | |
michael@0 | 1229 | RegCloseKey(subKey); |
michael@0 | 1230 | } |
michael@0 | 1231 | |
michael@0 | 1232 | // subkey for cleartype level, enhanced contrast |
michael@0 | 1233 | subrv = RegOpenKeyExW(HKEY_CURRENT_USER, |
michael@0 | 1234 | subkeyName, 0, KEY_QUERY_VALUE, &subKey); |
michael@0 | 1235 | |
michael@0 | 1236 | if (subrv == ERROR_SUCCESS) { |
michael@0 | 1237 | size = sizeof(value); |
michael@0 | 1238 | subrv = RegQueryValueExW(subKey, L"ClearTypeLevel", nullptr, &type, |
michael@0 | 1239 | (LPBYTE)&value, &size); |
michael@0 | 1240 | if (subrv == ERROR_SUCCESS && type == REG_DWORD) { |
michael@0 | 1241 | foundData = true; |
michael@0 | 1242 | ctinfo.clearTypeLevel = value; |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | size = sizeof(value); |
michael@0 | 1246 | subrv = RegQueryValueExW(subKey, L"EnhancedContrastLevel", |
michael@0 | 1247 | nullptr, &type, (LPBYTE)&value, &size); |
michael@0 | 1248 | if (subrv == ERROR_SUCCESS && type == REG_DWORD) { |
michael@0 | 1249 | foundData = true; |
michael@0 | 1250 | ctinfo.enhancedContrast = value; |
michael@0 | 1251 | } |
michael@0 | 1252 | |
michael@0 | 1253 | RegCloseKey(subKey); |
michael@0 | 1254 | } |
michael@0 | 1255 | |
michael@0 | 1256 | if (foundData) { |
michael@0 | 1257 | aParams.AppendElement(ctinfo); |
michael@0 | 1258 | } |
michael@0 | 1259 | } |
michael@0 | 1260 | |
michael@0 | 1261 | RegCloseKey(hKey); |
michael@0 | 1262 | } |
michael@0 | 1263 | |
michael@0 | 1264 | void |
michael@0 | 1265 | gfxWindowsPlatform::FontsPrefsChanged(const char *aPref) |
michael@0 | 1266 | { |
michael@0 | 1267 | bool clearTextFontCaches = true; |
michael@0 | 1268 | |
michael@0 | 1269 | gfxPlatform::FontsPrefsChanged(aPref); |
michael@0 | 1270 | |
michael@0 | 1271 | if (!aPref) { |
michael@0 | 1272 | mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; |
michael@0 | 1273 | mUseClearTypeAlways = UNINITIALIZED_VALUE; |
michael@0 | 1274 | } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) { |
michael@0 | 1275 | mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; |
michael@0 | 1276 | } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) { |
michael@0 | 1277 | mUseClearTypeAlways = UNINITIALIZED_VALUE; |
michael@0 | 1278 | } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) { |
michael@0 | 1279 | SetupClearTypeParams(); |
michael@0 | 1280 | } else { |
michael@0 | 1281 | clearTextFontCaches = false; |
michael@0 | 1282 | } |
michael@0 | 1283 | |
michael@0 | 1284 | if (clearTextFontCaches) { |
michael@0 | 1285 | gfxFontCache *fc = gfxFontCache::GetCache(); |
michael@0 | 1286 | if (fc) { |
michael@0 | 1287 | fc->Flush(); |
michael@0 | 1288 | } |
michael@0 | 1289 | } |
michael@0 | 1290 | } |
michael@0 | 1291 | |
michael@0 | 1292 | #define ENHANCED_CONTRAST_REGISTRY_KEY \ |
michael@0 | 1293 | HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel" |
michael@0 | 1294 | |
michael@0 | 1295 | void |
michael@0 | 1296 | gfxWindowsPlatform::SetupClearTypeParams() |
michael@0 | 1297 | { |
michael@0 | 1298 | #if CAIRO_HAS_DWRITE_FONT |
michael@0 | 1299 | if (GetDWriteFactory()) { |
michael@0 | 1300 | // any missing prefs will default to invalid (-1) and be ignored; |
michael@0 | 1301 | // out-of-range values will also be ignored |
michael@0 | 1302 | FLOAT gamma = -1.0; |
michael@0 | 1303 | FLOAT contrast = -1.0; |
michael@0 | 1304 | FLOAT level = -1.0; |
michael@0 | 1305 | int geometry = -1; |
michael@0 | 1306 | int mode = -1; |
michael@0 | 1307 | int32_t value; |
michael@0 | 1308 | if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) { |
michael@0 | 1309 | if (value >= 1000 && value <= 2200) { |
michael@0 | 1310 | gamma = FLOAT(value / 1000.0); |
michael@0 | 1311 | } |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) { |
michael@0 | 1315 | if (value >= 0 && value <= 1000) { |
michael@0 | 1316 | contrast = FLOAT(value / 100.0); |
michael@0 | 1317 | } |
michael@0 | 1318 | } |
michael@0 | 1319 | |
michael@0 | 1320 | if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) { |
michael@0 | 1321 | if (value >= 0 && value <= 100) { |
michael@0 | 1322 | level = FLOAT(value / 100.0); |
michael@0 | 1323 | } |
michael@0 | 1324 | } |
michael@0 | 1325 | |
michael@0 | 1326 | if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) { |
michael@0 | 1327 | if (value >= 0 && value <= 2) { |
michael@0 | 1328 | geometry = value; |
michael@0 | 1329 | } |
michael@0 | 1330 | } |
michael@0 | 1331 | |
michael@0 | 1332 | if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) { |
michael@0 | 1333 | if (value >= 0 && value <= 5) { |
michael@0 | 1334 | mode = value; |
michael@0 | 1335 | } |
michael@0 | 1336 | } |
michael@0 | 1337 | |
michael@0 | 1338 | cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode); |
michael@0 | 1339 | |
michael@0 | 1340 | switch (mode) { |
michael@0 | 1341 | case DWRITE_RENDERING_MODE_ALIASED: |
michael@0 | 1342 | case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: |
michael@0 | 1343 | mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; |
michael@0 | 1344 | break; |
michael@0 | 1345 | case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: |
michael@0 | 1346 | mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL; |
michael@0 | 1347 | break; |
michael@0 | 1348 | default: |
michael@0 | 1349 | mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; |
michael@0 | 1350 | break; |
michael@0 | 1351 | } |
michael@0 | 1352 | |
michael@0 | 1353 | nsRefPtr<IDWriteRenderingParams> defaultRenderingParams; |
michael@0 | 1354 | GetDWriteFactory()->CreateRenderingParams(getter_AddRefs(defaultRenderingParams)); |
michael@0 | 1355 | // For EnhancedContrast, we override the default if the user has not set it |
michael@0 | 1356 | // in the registry (by using the ClearType Tuner). |
michael@0 | 1357 | if (contrast >= 0.0 && contrast <= 10.0) { |
michael@0 | 1358 | contrast = contrast; |
michael@0 | 1359 | } else { |
michael@0 | 1360 | HKEY hKey; |
michael@0 | 1361 | if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY, |
michael@0 | 1362 | 0, KEY_READ, &hKey) == ERROR_SUCCESS) |
michael@0 | 1363 | { |
michael@0 | 1364 | contrast = defaultRenderingParams->GetEnhancedContrast(); |
michael@0 | 1365 | RegCloseKey(hKey); |
michael@0 | 1366 | } else { |
michael@0 | 1367 | contrast = 1.0; |
michael@0 | 1368 | } |
michael@0 | 1369 | } |
michael@0 | 1370 | |
michael@0 | 1371 | // For parameters that have not been explicitly set, |
michael@0 | 1372 | // we copy values from default params (or our overridden value for contrast) |
michael@0 | 1373 | if (gamma < 1.0 || gamma > 2.2) { |
michael@0 | 1374 | gamma = defaultRenderingParams->GetGamma(); |
michael@0 | 1375 | } |
michael@0 | 1376 | |
michael@0 | 1377 | if (level < 0.0 || level > 1.0) { |
michael@0 | 1378 | level = defaultRenderingParams->GetClearTypeLevel(); |
michael@0 | 1379 | } |
michael@0 | 1380 | |
michael@0 | 1381 | DWRITE_PIXEL_GEOMETRY dwriteGeometry = |
michael@0 | 1382 | static_cast<DWRITE_PIXEL_GEOMETRY>(geometry); |
michael@0 | 1383 | DWRITE_RENDERING_MODE renderMode = |
michael@0 | 1384 | static_cast<DWRITE_RENDERING_MODE>(mode); |
michael@0 | 1385 | |
michael@0 | 1386 | if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT || |
michael@0 | 1387 | dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) { |
michael@0 | 1388 | dwriteGeometry = defaultRenderingParams->GetPixelGeometry(); |
michael@0 | 1389 | } |
michael@0 | 1390 | |
michael@0 | 1391 | if (renderMode < DWRITE_RENDERING_MODE_DEFAULT || |
michael@0 | 1392 | renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) { |
michael@0 | 1393 | renderMode = defaultRenderingParams->GetRenderingMode(); |
michael@0 | 1394 | } |
michael@0 | 1395 | |
michael@0 | 1396 | mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams; |
michael@0 | 1397 | |
michael@0 | 1398 | GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level, |
michael@0 | 1399 | dwriteGeometry, renderMode, |
michael@0 | 1400 | getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL])); |
michael@0 | 1401 | |
michael@0 | 1402 | GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level, |
michael@0 | 1403 | dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, |
michael@0 | 1404 | getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC])); |
michael@0 | 1405 | } |
michael@0 | 1406 | #endif |
michael@0 | 1407 | } |
michael@0 | 1408 | |
michael@0 | 1409 | void |
michael@0 | 1410 | gfxWindowsPlatform::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager) |
michael@0 | 1411 | { |
michael@0 | 1412 | if (aDeviceManager == mDeviceManager) { |
michael@0 | 1413 | mDeviceManager = nullptr; |
michael@0 | 1414 | } |
michael@0 | 1415 | } |
michael@0 | 1416 | |
michael@0 | 1417 | IDirect3DDevice9* |
michael@0 | 1418 | gfxWindowsPlatform::GetD3D9Device() |
michael@0 | 1419 | { |
michael@0 | 1420 | DeviceManagerD3D9* manager = GetD3D9DeviceManager(); |
michael@0 | 1421 | return manager ? manager->device() : nullptr; |
michael@0 | 1422 | } |
michael@0 | 1423 | |
michael@0 | 1424 | DeviceManagerD3D9* |
michael@0 | 1425 | gfxWindowsPlatform::GetD3D9DeviceManager() |
michael@0 | 1426 | { |
michael@0 | 1427 | // We should only create the d3d9 device on the compositor thread |
michael@0 | 1428 | // or we don't have a compositor thread. |
michael@0 | 1429 | if (!mDeviceManager && |
michael@0 | 1430 | (CompositorParent::IsInCompositorThread() || |
michael@0 | 1431 | !CompositorParent::CompositorLoop())) { |
michael@0 | 1432 | mDeviceManager = new DeviceManagerD3D9(); |
michael@0 | 1433 | if (!mDeviceManager->Init()) { |
michael@0 | 1434 | NS_WARNING("Could not initialise device manager"); |
michael@0 | 1435 | mDeviceManager = nullptr; |
michael@0 | 1436 | } |
michael@0 | 1437 | } |
michael@0 | 1438 | |
michael@0 | 1439 | return mDeviceManager; |
michael@0 | 1440 | } |
michael@0 | 1441 | |
michael@0 | 1442 | ID3D11Device* |
michael@0 | 1443 | gfxWindowsPlatform::GetD3D11Device() |
michael@0 | 1444 | { |
michael@0 | 1445 | if (mD3D11DeviceInitialized) { |
michael@0 | 1446 | return mD3D11Device; |
michael@0 | 1447 | } |
michael@0 | 1448 | |
michael@0 | 1449 | mD3D11DeviceInitialized = true; |
michael@0 | 1450 | |
michael@0 | 1451 | nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll")); |
michael@0 | 1452 | decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*) |
michael@0 | 1453 | GetProcAddress(d3d11Module, "D3D11CreateDevice"); |
michael@0 | 1454 | |
michael@0 | 1455 | if (!d3d11CreateDevice) { |
michael@0 | 1456 | return nullptr; |
michael@0 | 1457 | } |
michael@0 | 1458 | |
michael@0 | 1459 | nsTArray<D3D_FEATURE_LEVEL> featureLevels; |
michael@0 | 1460 | if (IsWin8OrLater()) { |
michael@0 | 1461 | featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); |
michael@0 | 1462 | } |
michael@0 | 1463 | featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); |
michael@0 | 1464 | featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); |
michael@0 | 1465 | featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); |
michael@0 | 1466 | featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); |
michael@0 | 1467 | |
michael@0 | 1468 | RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter(); |
michael@0 | 1469 | |
michael@0 | 1470 | if (!adapter) { |
michael@0 | 1471 | return nullptr; |
michael@0 | 1472 | } |
michael@0 | 1473 | |
michael@0 | 1474 | HRESULT hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, |
michael@0 | 1475 | D3D11_CREATE_DEVICE_BGRA_SUPPORT, |
michael@0 | 1476 | featureLevels.Elements(), featureLevels.Length(), |
michael@0 | 1477 | D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr); |
michael@0 | 1478 | |
michael@0 | 1479 | // We leak these everywhere and we need them our entire runtime anyway, let's |
michael@0 | 1480 | // leak it here as well. |
michael@0 | 1481 | d3d11Module.disown(); |
michael@0 | 1482 | |
michael@0 | 1483 | return mD3D11Device; |
michael@0 | 1484 | } |
michael@0 | 1485 | |
michael@0 | 1486 | bool |
michael@0 | 1487 | gfxWindowsPlatform::IsOptimus() |
michael@0 | 1488 | { |
michael@0 | 1489 | return GetModuleHandleA("nvumdshim.dll"); |
michael@0 | 1490 | } |
michael@0 | 1491 | |
michael@0 | 1492 | int |
michael@0 | 1493 | gfxWindowsPlatform::GetScreenDepth() const |
michael@0 | 1494 | { |
michael@0 | 1495 | // if the system doesn't have all displays with the same |
michael@0 | 1496 | // pixel format, just return 24 and move on with life. |
michael@0 | 1497 | if (!GetSystemMetrics(SM_SAMEDISPLAYFORMAT)) |
michael@0 | 1498 | return 24; |
michael@0 | 1499 | |
michael@0 | 1500 | HDC hdc = GetDC(nullptr); |
michael@0 | 1501 | if (!hdc) |
michael@0 | 1502 | return 24; |
michael@0 | 1503 | |
michael@0 | 1504 | int depth = GetDeviceCaps(hdc, BITSPIXEL) * |
michael@0 | 1505 | GetDeviceCaps(hdc, PLANES); |
michael@0 | 1506 | |
michael@0 | 1507 | ReleaseDC(nullptr, hdc); |
michael@0 | 1508 | |
michael@0 | 1509 | return depth; |
michael@0 | 1510 | } |
michael@0 | 1511 | |
michael@0 | 1512 | IDXGIAdapter1* |
michael@0 | 1513 | gfxWindowsPlatform::GetDXGIAdapter() |
michael@0 | 1514 | { |
michael@0 | 1515 | if (mAdapter) { |
michael@0 | 1516 | return mAdapter; |
michael@0 | 1517 | } |
michael@0 | 1518 | |
michael@0 | 1519 | nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); |
michael@0 | 1520 | decltype(CreateDXGIFactory1)* createDXGIFactory1 = (decltype(CreateDXGIFactory1)*) |
michael@0 | 1521 | GetProcAddress(dxgiModule, "CreateDXGIFactory1"); |
michael@0 | 1522 | |
michael@0 | 1523 | // Try to use a DXGI 1.1 adapter in order to share resources |
michael@0 | 1524 | // across processes. |
michael@0 | 1525 | if (createDXGIFactory1) { |
michael@0 | 1526 | nsRefPtr<IDXGIFactory1> factory1; |
michael@0 | 1527 | HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1), |
michael@0 | 1528 | getter_AddRefs(factory1)); |
michael@0 | 1529 | |
michael@0 | 1530 | if (FAILED(hr) || !factory1) { |
michael@0 | 1531 | // This seems to happen with some people running the iZ3D driver. |
michael@0 | 1532 | // They won't get acceleration. |
michael@0 | 1533 | return nullptr; |
michael@0 | 1534 | } |
michael@0 | 1535 | |
michael@0 | 1536 | hr = factory1->EnumAdapters1(0, byRef(mAdapter)); |
michael@0 | 1537 | if (FAILED(hr)) { |
michael@0 | 1538 | // We should return and not accelerate if we can't obtain |
michael@0 | 1539 | // an adapter. |
michael@0 | 1540 | return nullptr; |
michael@0 | 1541 | } |
michael@0 | 1542 | } |
michael@0 | 1543 | |
michael@0 | 1544 | // We leak this module everywhere, we might as well do so here as well. |
michael@0 | 1545 | dxgiModule.disown(); |
michael@0 | 1546 | |
michael@0 | 1547 | return mAdapter; |
michael@0 | 1548 | } |