gfxVars.cpp (5125B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "gfxVars.h" 8 #include "gfxVarReceiver.h" 9 #include "mozilla/dom/ContentChild.h" 10 11 namespace mozilla { 12 namespace gfx { 13 14 StaticAutoPtr<gfxVars> gfxVars::sInstance; 15 StaticAutoPtr<nsTArray<gfxVars::VarBase*>> gfxVars::sVarList; 16 17 // Used only during initialization to store pending updates if received prior to 18 // gfxVars::Initialize. 19 StaticAutoPtr<nsTArray<GfxVarUpdate>> gGfxVarInitUpdates; 20 21 // Used only after initialization to store pending updates for 22 // gfxVarsCollectUpdates that will be dispatched once it goes out of scope. This 23 // is useful when we are changing multiple gfxVars and wish to only update the 24 // child processes once. 25 StaticAutoPtr<nsTArray<GfxVarUpdate>> gGfxVarPendingUpdates; 26 27 void gfxVars::SetValuesForInitialize( 28 const nsTArray<GfxVarUpdate>& aInitUpdates) { 29 // This should only be called once 30 MOZ_RELEASE_ASSERT(!gGfxVarInitUpdates); 31 32 // We expect aInitUpdates to be provided before any other gfxVars operation, 33 // and for sInstance to be null here, but handle the alternative. 34 if (sInstance) { 35 // Apply the updates, the object has been created already 36 ApplyUpdate(aInitUpdates); 37 } else { 38 // Save the values for Initialize call 39 gGfxVarInitUpdates = new nsTArray<GfxVarUpdate>(aInitUpdates.Clone()); 40 } 41 } 42 43 void gfxVars::StartCollectingUpdates() { 44 MOZ_RELEASE_ASSERT(XRE_IsParentProcess()); 45 MOZ_RELEASE_ASSERT(sInstance); 46 MOZ_RELEASE_ASSERT(!gGfxVarPendingUpdates); 47 gGfxVarPendingUpdates = new nsTArray<GfxVarUpdate>(); 48 } 49 50 void gfxVars::StopCollectingUpdates() { 51 MOZ_RELEASE_ASSERT(XRE_IsParentProcess()); 52 MOZ_RELEASE_ASSERT(sInstance); 53 MOZ_RELEASE_ASSERT(gGfxVarPendingUpdates); 54 if (!gGfxVarPendingUpdates->IsEmpty()) { 55 for (auto& receiver : sInstance->mReceivers) { 56 receiver->OnVarChanged(*gGfxVarPendingUpdates); 57 } 58 } 59 gGfxVarPendingUpdates = nullptr; 60 } 61 62 void gfxVars::Initialize() { 63 if (sInstance) { 64 MOZ_RELEASE_ASSERT( 65 !gGfxVarInitUpdates, 66 "Initial updates should not be present after any gfxVars operation"); 67 return; 68 } 69 70 // sVarList must be initialized first since it's used in the constructor for 71 // sInstance. 72 sVarList = new nsTArray<gfxVars::VarBase*>(); 73 sInstance = new gfxVars; 74 75 // Content processes should have gotten a call to SetValuesForInitialize, 76 // which will have set gGfxVarInitUpdates. 77 MOZ_ASSERT_IF(XRE_IsContentProcess(), gGfxVarInitUpdates); 78 79 if (gGfxVarInitUpdates) { 80 // Apply any updates from gGfxVarInitUpdates. 81 ApplyUpdate(*gGfxVarInitUpdates); 82 gGfxVarInitUpdates = nullptr; 83 } 84 } 85 86 gfxVars::gfxVars() = default; 87 88 void gfxVars::Shutdown() { 89 sInstance = nullptr; 90 sVarList = nullptr; 91 gGfxVarInitUpdates = nullptr; 92 } 93 94 /* static */ 95 void gfxVars::ApplyUpdate(const nsTArray<GfxVarUpdate>& aUpdate) { 96 // Only subprocesses receive updates and apply them locally. 97 MOZ_ASSERT(!XRE_IsParentProcess()); 98 MOZ_DIAGNOSTIC_ASSERT(sVarList || gGfxVarInitUpdates); 99 if (sVarList) { 100 for (auto& i : aUpdate) { 101 sVarList->ElementAt(i.index())->SetValue(i.value()); 102 } 103 } else if (gGfxVarInitUpdates) { 104 // Too early, we haven't been initialized, so just add to 105 // the array waiting for the initialization... 106 gGfxVarInitUpdates->AppendElements(aUpdate); 107 } 108 } 109 110 /* static */ 111 void gfxVars::AddReceiver(gfxVarReceiver* aReceiver) { 112 MOZ_ASSERT(NS_IsMainThread()); 113 114 // Don't double-add receivers, in case a broken content process sends two 115 // init messages. 116 if (!sInstance->mReceivers.Contains(aReceiver)) { 117 sInstance->mReceivers.AppendElement(aReceiver); 118 } 119 } 120 121 /* static */ 122 void gfxVars::RemoveReceiver(gfxVarReceiver* aReceiver) { 123 MOZ_ASSERT(NS_IsMainThread()); 124 125 if (sInstance) { 126 sInstance->mReceivers.RemoveElement(aReceiver); 127 } 128 } 129 130 /* static */ 131 nsTArray<GfxVarUpdate> gfxVars::FetchNonDefaultVars() { 132 MOZ_ASSERT(NS_IsMainThread()); 133 MOZ_ASSERT(sVarList); 134 135 nsTArray<GfxVarUpdate> updates; 136 for (size_t i = 0; i < sVarList->Length(); i++) { 137 VarBase* var = sVarList->ElementAt(i); 138 if (var->HasDefaultValue()) { 139 continue; 140 } 141 142 GfxVarValue value; 143 var->GetValue(&value); 144 145 updates.AppendElement(GfxVarUpdate(i, value)); 146 } 147 148 return updates; 149 } 150 151 gfxVars::VarBase::VarBase() { 152 mIndex = gfxVars::sVarList->Length(); 153 gfxVars::sVarList->AppendElement(this); 154 } 155 156 void gfxVars::NotifyReceivers(VarBase* aVar) { 157 MOZ_ASSERT(NS_IsMainThread()); 158 159 GfxVarValue value; 160 aVar->GetValue(&value); 161 162 if (XRE_IsParentProcess() && gGfxVarPendingUpdates) { 163 gGfxVarPendingUpdates->AppendElement(GfxVarUpdate(aVar->Index(), value)); 164 return; 165 } 166 167 AutoTArray<GfxVarUpdate, 1> vars; 168 vars.AppendElement(GfxVarUpdate(aVar->Index(), value)); 169 170 for (auto& receiver : mReceivers) { 171 receiver->OnVarChanged(vars); 172 } 173 } 174 175 } // namespace gfx 176 } // namespace mozilla