WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-90869-20120712141458.patch (text/plain), 18.58 KB, created by
Kwonjin Jeong
on 2012-07-11 22:15:00 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Kwonjin Jeong
Created:
2012-07-11 22:15:00 PDT
Size:
18.58 KB
patch
obsolete
>Subversion Revision: 122323 >diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog >index 782784448edda53d9fd226e7dcfe4d022d0cc642..22b74eabd3e83ac446d12d936ab28285a304679b 100644 >--- a/Source/WTF/ChangeLog >+++ b/Source/WTF/ChangeLog >@@ -1,5 +1,27 @@ > 2012-07-11 Kwonjin Jeong <gram@company100.net> > >+ Add ImageDecodeWorker >+ https://bugs.webkit.org/show_bug.cgi?id=90869 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ ImageDecodeWorker is a thread pool implementation based on WorkQueue. >+ ImageDecodeWorker internally manages a pool of WorkQueues (n = number >+ of cores) and assigns one from the pool when an ImageDecodeWorker >+ instance is created. So two ImageDecodeWorkers can share one WorkQueue. >+ >+ Parallel image decoders create an instance of ImageDecodeWorker for >+ each image. So the number of ImageDecodeWorker instances can be >+ arbitrarily large, but the number of WorkQueues is limited to the >+ number of cores. This effectively utilizes the underlying cores. >+ >+ * wtf/chromium/MainThreadChromium.cpp: >+ (WTF::callFunctionObject): >+ (WTF): >+ (WTF::callOnMainThread): >+ >+2012-07-11 Kwonjin Jeong <gram@company100.net> >+ > Move WorkQueue to WTF > https://bugs.webkit.org/show_bug.cgi?id=90780 > >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 96dd7aad2811559b3c1fa85a3cb392932d6fd62d..b35f745c6a5e0112414506aaec8de06116f465dc 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,42 @@ >+2012-07-11 Kwonjin Jeong <gram@company100.net> >+ >+ Add ImageDecodeWorker >+ https://bugs.webkit.org/show_bug.cgi?id=90869 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ ImageDecodeWorker is a thread pool implementation based on WorkQueue. >+ ImageDecodeWorker internally manages a pool of WorkQueues (n = number >+ of cores) and assigns one from the pool when an ImageDecodeWorker >+ instance is created. So two ImageDecodeWorkers can share one WorkQueue. >+ >+ Parallel image decoders create an instance of ImageDecodeWorker for >+ each image. So the number of ImageDecodeWorker instances can be >+ arbitrarily large, but the number of WorkQueues is limited to the >+ number of cores. This effectively utilizes the underlying cores. >+ >+ * CMakeLists.txt: >+ * GNUmakefile.list.am: >+ * Target.pri: >+ * WebCore.gypi: >+ * WebCore.vcproj/WebCore.vcproj: >+ * WebCore.xcodeproj/project.pbxproj: >+ * platform/graphics/ImageDecodeWorker.cpp: Added. >+ (WebCore): >+ (WebCore::ImageDecodeWorker::acquireSharedWorker): >+ (WebCore::ImageDecodeWorker::initializeWorkQueuePool): >+ (WebCore::ImageDecodeWorker::queueIdWithMinimumAcquireCount): >+ (WebCore::ImageDecodeWorker::ImageDecodeWorker): >+ (WebCore::ImageDecodeWorker::~ImageDecodeWorker): >+ (WebCore::ImageDecodeWorker::hasInvalidationBegun): >+ (WebCore::ImageDecodeWorker::cancelableFunction): >+ (WebCore::ImageDecodeWorker::postTask): >+ (WebCore::ImageDecodeWorker::invalidate): >+ (WebCore::ImageDecodeWorker::ensureTerminate): >+ * platform/graphics/ImageDecodeWorker.h: Added. >+ (WebCore): >+ (ImageDecodeWorker): >+ > 2012-07-11 Yoshifumi Inoue <yosin@chromium.org> > > [Mac] Expose time format related functions >diff --git a/Source/WTF/wtf/chromium/MainThreadChromium.cpp b/Source/WTF/wtf/chromium/MainThreadChromium.cpp >index 9e6592b5715679ae2bc9a6d1a0b6f3b8c9e18e81..ae5fc8196b1ca69fa2a1514ee286c13f9e724203 100644 >--- a/Source/WTF/wtf/chromium/MainThreadChromium.cpp >+++ b/Source/WTF/wtf/chromium/MainThreadChromium.cpp >@@ -33,6 +33,7 @@ > > #include "Assertions.h" > #include "ChromiumThreading.h" >+#include "Functional.h" > #include "Threading.h" > > namespace WTF { >@@ -54,6 +55,18 @@ void callOnMainThread(MainThreadFunction* function, void* context) > ChromiumThreading::callOnMainThread(function, context); > } > >+static void callFunctionObject(void* context) >+{ >+ Function<void()>* function = static_cast<Function<void()>*>(context); >+ (*function)(); >+ delete function; >+} >+ >+void callOnMainThread(const Function<void()>& function) >+{ >+ callOnMainThread(callFunctionObject, new Function<void ()>(function)); >+} >+ > void callOnMainThreadAndWait(MainThreadFunction*, void*) > { > ASSERT_NOT_REACHED(); >diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt >index e0737d8fd5c83137787ddb2f010791fc927fab78..6d17219f064462061de5770956142e22d6a7053e 100644 >--- a/Source/WebCore/CMakeLists.txt >+++ b/Source/WebCore/CMakeLists.txt >@@ -1194,6 +1194,7 @@ SET(WebCore_SOURCES > platform/graphics/GraphicsTypes.cpp > platform/graphics/Image.cpp > platform/graphics/ImageBuffer.cpp >+ platform/graphics/ImageDecodeWorker.cpp > platform/graphics/ImageOrientation.cpp > platform/graphics/IntRect.cpp > platform/graphics/Path.cpp >diff --git a/Source/WebCore/GNUmakefile.list.am b/Source/WebCore/GNUmakefile.list.am >index 3781727aa6a0e4e154e9ebf7619ea9f2ce3c843c..e8dc706007363fc3595acfe98fcb6a251669c4d8 100644 >--- a/Source/WebCore/GNUmakefile.list.am >+++ b/Source/WebCore/GNUmakefile.list.am >@@ -3355,6 +3355,8 @@ webcore_sources += \ > Source/WebCore/platform/graphics/ImageBufferData.h \ > Source/WebCore/platform/graphics/Image.cpp \ > Source/WebCore/platform/graphics/Image.h \ >+ Source/WebCore/platform/graphics/ImageDecodeBuffer.cpp \ >+ Source/WebCore/platform/graphics/ImageDecodeBuffer.h \ > Source/WebCore/platform/graphics/ImageObserver.h \ > Source/WebCore/platform/graphics/ImageOrientation.cpp \ > Source/WebCore/platform/graphics/ImageOrientation.h \ >diff --git a/Source/WebCore/Target.pri b/Source/WebCore/Target.pri >index b91497553f4a0e4b934cc5af4c4a627520632f58..b8cad571624283c496904cc62f07a2e11ee707c7 100644 >--- a/Source/WebCore/Target.pri >+++ b/Source/WebCore/Target.pri >@@ -1122,6 +1122,7 @@ SOURCES += \ > platform/graphics/GraphicsTypes.cpp \ > platform/graphics/Image.cpp \ > platform/graphics/ImageBuffer.cpp \ >+ platform/graphics/ImageDecodeWorker.cpp \ > platform/graphics/ImageOrientation.cpp \ > platform/graphics/ImageSource.cpp \ > platform/graphics/IntRect.cpp \ >@@ -2298,6 +2299,7 @@ HEADERS += \ > platform/graphics/GraphicsTypes.h \ > platform/graphics/GraphicsTypes3D.h \ > platform/graphics/Image.h \ >+ platform/graphics/ImageDecodeWorker.h \ > platform/graphics/ImageOrientation.h \ > platform/graphics/ImageSource.h \ > platform/graphics/IntPoint.h \ >diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi >index 9b68d3ef399ef3145c4c31cb5ebe9f94942c56aa..e31f14ba85bb9a2bfdd042955c3eb1cbfd7d8001 100644 >--- a/Source/WebCore/WebCore.gypi >+++ b/Source/WebCore/WebCore.gypi >@@ -382,6 +382,7 @@ > 'platform/graphics/Image.h', > 'platform/graphics/ImageBuffer.h', > 'platform/graphics/ImageBufferData.h', >+ 'platform/graphics/ImageDecodeBuffer.h', > 'platform/graphics/ImageObserver.h', > 'platform/graphics/ImageOrientation.h', > 'platform/graphics/ImageSource.h', >@@ -3495,6 +3496,7 @@ > 'platform/graphics/GraphicsTypes.cpp', > 'platform/graphics/Image.cpp', > 'platform/graphics/ImageBuffer.cpp', >+ 'platform/graphics/ImageDecodeBuffer.cpp', > 'platform/graphics/ImageOrientation.cpp', > 'platform/graphics/ImageSource.cpp', > 'platform/graphics/IntRect.cpp', >diff --git a/Source/WebCore/WebCore.vcproj/WebCore.vcproj b/Source/WebCore/WebCore.vcproj/WebCore.vcproj >index 9062c8b231f6c0a5aa3bd1a94b51f4d48fd38834..497ee8f0ba0126ddfe7eac13c94d924586c1dab0 100755 >--- a/Source/WebCore/WebCore.vcproj/WebCore.vcproj >+++ b/Source/WebCore/WebCore.vcproj/WebCore.vcproj >@@ -29298,6 +29298,14 @@ > > > </File> > <File >+ RelativePath="..\platform\graphics\ImageDecodeWorker.cpp" >+ > >+ </File> >+ <File >+ RelativePath="..\platform\graphics\ImageDecodeWorker.h" >+ > >+ </File> >+ <File > RelativePath="..\platform\graphics\ImageObserver.h" > > > </File> >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index c126c95af9c995781a6a0c1e342474f24485ac50..aff6f986f4f40dd371df3709cd3576265bfecba2 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -6480,6 +6480,8 @@ > FE80DA720E9C472F000D6F75 /* JSPositionError.h in Headers */ = {isa = PBXBuildFile; fileRef = FE80DA6E0E9C472F000D6F75 /* JSPositionError.h */; }; > FFD5B97A135CC97800D5E92A /* PageVisibilityState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */; }; > FFD5B97B135CC97800D5E92A /* PageVisibilityState.h in Headers */ = {isa = PBXBuildFile; fileRef = FFD5B978135CC97800D5E92A /* PageVisibilityState.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ FFD6B97A135CC97800D5E92A /* ImageDecodeWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFD6B96A135CC97800D5E92A /* ImageDecodeWorker.cpp */; }; >+ FFD6B97B135CC97800D5E92A /* ImageDecodeWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = FFD6B96B135CC97800D5E92A /* ImageDecodeWorker.h */; }; > /* End PBXBuildFile section */ > > /* Begin PBXContainerItemProxy section */ >@@ -13815,6 +13817,8 @@ > FE80DA6E0E9C472F000D6F75 /* JSPositionError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPositionError.h; sourceTree = "<group>"; }; > FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageVisibilityState.cpp; sourceTree = "<group>"; }; > FFD5B978135CC97800D5E92A /* PageVisibilityState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageVisibilityState.h; sourceTree = "<group>"; }; >+ FFD6B96A135CC97800D5E92A /* ImageDecodeWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecodeWorker.cpp; sourceTree = "<group>"; }; >+ FFD6B97B135CC97800D5E92A /* ImageDecodeWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecodeWorker.h; sourceTree = "<group>"; }; > /* End PBXFileReference section */ > > /* Begin PBXFrameworksBuildPhase section */ >@@ -19675,6 +19679,8 @@ > 43D2597613C816F400608559 /* ImageBuffer.cpp */, > B2A10B910B3818BD00099AA4 /* ImageBuffer.h */, > 22BD9F7D1353625C009BD102 /* ImageBufferData.h */, >+ FFD6B96A135CC97800D5E92A /* ImageDecodeWorker.cpp */ >+ FFD6B96A135CC97800D5E92A /* ImageDecodeWorker.h */ > BC7F44A70B9E324E00A9D081 /* ImageObserver.h */, > A8748D7412CC3F89001FBA41 /* ImageOrientation.cpp */, > A8748D6612CC3763001FBA41 /* ImageOrientation.h */, >diff --git a/Source/WebCore/platform/graphics/ImageDecodeWorker.cpp b/Source/WebCore/platform/graphics/ImageDecodeWorker.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..2b2580d6f967120c3f8c2e98e1b7d2d1a0d65bbe >--- /dev/null >+++ b/Source/WebCore/platform/graphics/ImageDecodeWorker.cpp >@@ -0,0 +1,134 @@ >+/* >+ * Copyright (C) 2012 Company 100 Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ImageDecodeWorker.h" >+ >+#include <limits> >+ >+#include <wtf/NumberOfCores.h> >+#include <wtf/WorkQueue.h> >+#include <wtf/text/CString.h> >+#include <wtf/text/WTFString.h> >+ >+namespace WebCore { >+ >+Vector<WorkQueue*>* ImageDecodeWorker::s_workQueuePool = 0; >+int* ImageDecodeWorker::s_workQueueAcquireCount = 0; >+ >+PassRefPtr<ImageDecodeWorker> ImageDecodeWorker::acquireSharedWorker() >+{ >+ if (!s_workQueuePool) >+ initializeWorkQueuePool(); >+ >+ return adoptRef(new ImageDecodeWorker()); >+} >+ >+void ImageDecodeWorker::initializeWorkQueuePool() >+{ >+ const int numCores = WTF::numberOfProcessorCores(); >+ >+ s_workQueueAcquireCount = new int[numCores]; >+ s_workQueuePool = new Vector<WorkQueue*>(); >+ s_workQueuePool->reserveInitialCapacity(numCores); >+ for (int i = 0; i < numCores; i++) { >+ s_workQueueAcquireCount[i] = 0; >+ String queueName = "ImageDecodeWorker." + String::number(i); >+ s_workQueuePool->append(new WorkQueue(queueName.ascii().data())); >+ } >+} >+ >+int ImageDecodeWorker::queueIdWithMinimumAcquireCount() >+{ >+ int minimumAcquireCount = std::numeric_limits<int>::max(); >+ int index = s_workQueuePool->size(); >+ >+ for (size_t i = 0; i < s_workQueuePool->size(); i++) { >+ if (s_workQueueAcquireCount[i] < minimumAcquireCount) { >+ minimumAcquireCount = s_workQueueAcquireCount[i]; >+ index = i; >+ } >+ } >+ >+ ASSERT(index < s_workQueuePool->size()); >+ return index; >+} >+ >+ImageDecodeWorker::ImageDecodeWorker() >+ : m_workerStatus(Running) >+{ >+ m_workQueueId = queueIdWithMinimumAcquireCount(); >+ m_workQueue = (*s_workQueuePool)[m_workQueueId]; >+ s_workQueueAcquireCount[m_workQueueId]++; >+} >+ >+ImageDecodeWorker::~ImageDecodeWorker() >+{ >+} >+ >+bool ImageDecodeWorker::hasInvalidationBegun() >+{ >+ MutexLocker locker(m_workerStatusMutex); >+ if (m_workerStatus == InvalidationBegun) { >+ m_workerStatus = InvaidationReady; >+ m_invalidationReady.signal(); >+ } >+ return m_workerStatus != Running; >+} >+ >+void ImageDecodeWorker::cancelableFunction(PassRefPtr<ImageDecodeWorker> worker, const Function<void()>& function) >+{ >+ if (UNLIKELY(worker->hasInvalidationBegun())) >+ return; >+ >+ function(); >+} >+ >+void ImageDecodeWorker::postTask(const Function<void()>& function) >+{ >+ ASSERT(m_workerStatus == Running); >+ m_workQueue->dispatch(bind(ImageDecodeWorker::cancelableFunction, this, function)); >+} >+ >+void ImageDecodeWorker::invalidate() >+{ >+ MutexLocker locker(m_workerStatusMutex); >+ m_workerStatus = InvalidationBegun; >+ >+ m_workQueue->dispatch(bind(&ImageDecodeWorker::ensureTerminate, this)); >+ while (m_workerStatus != InvaidationReady) >+ m_invalidationReady.wait(m_workerStatusMutex); >+ s_workQueueAcquireCount[m_workQueueId]--; >+} >+ >+void ImageDecodeWorker::ensureTerminate(PassRefPtr<ImageDecodeWorker> worker) >+{ >+ MutexLocker locker(worker->m_workerStatusMutex); >+ ASSERT(worker->m_workerStatus != Running); >+ worker->m_workerStatus = InvaidationReady; >+ worker->m_invalidationReady.signal(); >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/ImageDecodeWorker.h b/Source/WebCore/platform/graphics/ImageDecodeWorker.h >new file mode 100644 >index 0000000000000000000000000000000000000000..e5d1a0bafdfcf4d35d17b1f5770dd41f899397c8 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/ImageDecodeWorker.h >@@ -0,0 +1,75 @@ >+/* >+ * Copyright (C) 2012 Company 100 Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef ImageDecodeWorker_h >+#define ImageDecodeWorker_h >+ >+#include <wtf/Functional.h> >+#include <wtf/RefCounted.h> >+#include <wtf/WorkQueue.h> >+ >+class WorkQueue; >+ >+namespace WebCore { >+ >+class ImageDecodeWorker : public ThreadSafeRefCounted<ImageDecodeWorker> { >+public: >+ static PassRefPtr<ImageDecodeWorker> acquireSharedWorker(); >+ >+ virtual ~ImageDecodeWorker(); >+ >+ void postTask(const Function<void()>&); >+ void invalidate(); >+ >+private: >+ static void initializeWorkQueuePool(); >+ static int queueIdWithMinimumAcquireCount(); >+ >+ // FIXME: These two static functions should become non-static methods. >+ // However, defining them as non-static methods causes an unintended destructor >+ // call while a Function object passed WorkQueue::dispatch() is being destructed. >+ // To avoid this problem, these functions are defined as static methods. >+ static void cancelableFunction(PassRefPtr<ImageDecodeWorker>, const Function<void()>&); >+ static void ensureTerminate(PassRefPtr<ImageDecodeWorker>); >+ >+ ImageDecodeWorker(); >+ >+ bool hasInvalidationBegun(); >+ >+ static Vector<WorkQueue*>* s_workQueuePool; >+ static int* s_workQueueAcquireCount; >+ >+ enum WorkerStatus { Running, InvalidationBegun, InvaidationReady }; >+ Mutex m_workerStatusMutex; >+ WorkerStatus m_workerStatus; >+ ThreadCondition m_invalidationReady; >+ >+ int m_workQueueId; >+ WorkQueue* m_workQueue; >+}; >+ >+} // namespace WebCore >+ >+#endif // ImageDecodeWorker_h
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 90869
:
151656
|
151666
|
151667
|
151857
|
151866
|
151872
|
152695