LayoutTestController.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
1ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block/* 2ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * Copyright (C) 2010 Apple Inc. All rights reserved. 3ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * 4ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * Redistribution and use in source and binary forms, with or without 5ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * modification, are permitted provided that the following conditions 6ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * are met: 7ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * 1. Redistributions of source code must retain the above copyright 8ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * notice, this list of conditions and the following disclaimer. 9ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * 2. Redistributions in binary form must reproduce the above copyright 10ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * notice, this list of conditions and the following disclaimer in the 11ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * documentation and/or other materials provided with the distribution. 12ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * 13ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block * THE POSSIBILITY OF SUCH DAMAGE. 24ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block */ 25ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 262bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "config.h" 27ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block#include "LayoutTestController.h" 28967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 29e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include "InjectedBundle.h" 30e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include "InjectedBundlePage.h" 31967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#include "JSLayoutTestController.h" 32dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#include "StringFunctions.h" 33e14391e94c850b8bd03680c23b38978db68687a8John Reck#include <WebKit2/WKBundleBackForwardList.h> 34e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <WebKit2/WKBundleFrame.h> 350617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen#include <WebKit2/WKBundleFramePrivate.h> 362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <WebKit2/WKBundleInspector.h> 370617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen#include <WebKit2/WKBundlePagePrivate.h> 385ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include <WebKit2/WKBundleScriptWorld.h> 39dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#include <WebKit2/WKBundlePrivate.h> 40e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <WebKit2/WKRetainPtr.h> 41e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <WebKit2/WebKit2.h> 42ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#include <wtf/HashMap.h> 43ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 44ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blocknamespace WTR { 45ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 460617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen// This is lower than DumpRenderTree's timeout, to make it easier to work through the failures 470617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen// Eventually it should be changed to match. 4868513a70bcd92384395513322f1b801e7bf9c729Steve Blockconst double LayoutTestController::waitToDumpWatchdogTimerInterval = 6; 490617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 500617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenstatic JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName) 510617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 520617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!object) 530617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 540617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName)); 550617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef exception; 560617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return JSObjectGetProperty(context, object, propertyNameString.get(), &exception); 570617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 580617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 590617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenstatic JSObjectRef propertyObject(JSContextRef context, JSObjectRef object, const char* propertyName) 600617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 610617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef value = propertyValue(context, object, propertyName); 620617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!value || !JSValueIsObject(context, value)) 630617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 640617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return const_cast<JSObjectRef>(value); 650617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 660617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 670617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenstatic JSObjectRef getElementById(WKBundleFrameRef frame, JSStringRef elementId) 68ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{ 690617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); 700617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSObjectRef document = propertyObject(context, JSContextGetGlobalObject(context), "document"); 710617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!document) 720617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 730617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef getElementById = propertyObject(context, document, "getElementById"); 740617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!getElementById || !JSValueIsObject(context, getElementById)) 750617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 760617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef elementIdValue = JSValueMakeString(context, elementId); 770617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef exception; 780617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef element = JSObjectCallAsFunction(context, const_cast<JSObjectRef>(getElementById), document, 1, &elementIdValue, &exception); 790617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!element || !JSValueIsObject(context, element)) 800617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 810617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return const_cast<JSObjectRef>(element); 82ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block} 83ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 840617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenPassRefPtr<LayoutTestController> LayoutTestController::create() 850617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 860617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return adoptRef(new LayoutTestController); 870617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 880617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 890617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenLayoutTestController::LayoutTestController() 900617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen : m_whatToDump(RenderTree) 910617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen , m_shouldDumpAllFrameScrollPositions(false) 92e14391e94c850b8bd03680c23b38978db68687a8John Reck , m_shouldDumpBackForwardListsForAllWindows(false) 930617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen , m_shouldAllowEditing(true) 94db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block , m_shouldCloseExtraWindows(false) 950617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen , m_dumpEditingCallbacks(false) 96967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch , m_dumpStatusCallbacks(false) 97dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch , m_dumpTitleChanges(false) 9881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch , m_dumpPixels(true) 99e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke , m_waitToDump(false) 100967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch , m_testRepaint(false) 101967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch , m_testRepaintSweepHorizontally(false) 1022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block , m_willSendRequestReturnsNull(false) 103ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{ 10468513a70bcd92384395513322f1b801e7bf9c729Steve Block platformInitialize(); 105ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block} 106ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 107ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve BlockLayoutTestController::~LayoutTestController() 108ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{ 109ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block} 110ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 111967717af5423377c967781471ee106e2bb4e11c8Ben MurdochJSClassRef LayoutTestController::wrapperClass() 112967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 113967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return JSLayoutTestController::layoutTestControllerClass(); 114967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch} 115e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 116967717af5423377c967781471ee106e2bb4e11c8Ben Murdochvoid LayoutTestController::display() 117967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 118967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch // FIXME: actually implement, once we want pixel tests 119967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch} 120e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 12181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid LayoutTestController::dumpAsText() 12281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{ 12381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_whatToDump = MainFrameText; 12481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_dumpPixels = false; 12581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch} 12681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 127967717af5423377c967781471ee106e2bb4e11c8Ben Murdochvoid LayoutTestController::waitUntilDone() 128e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 129e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke m_waitToDump = true; 13068513a70bcd92384395513322f1b801e7bf9c729Steve Block initializeWaitToDumpWatchdogTimerIfNeeded(); 131e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 132e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 133e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkevoid LayoutTestController::waitToDumpWatchdogTimerFired() 134e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 13568513a70bcd92384395513322f1b801e7bf9c729Steve Block invalidateWaitToDumpWatchdogTimer(); 136e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke const char* message = "FAIL: Timed out waiting for notifyDone to be called\n"; 137e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke InjectedBundle::shared().os() << message << "\n"; 138e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke InjectedBundle::shared().done(); 139e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 140e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 141e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkevoid LayoutTestController::notifyDone() 142e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 143cad810f21b803229eb11403f9209855525a25d57Steve Block if (!InjectedBundle::shared().isTestRunning()) 144cad810f21b803229eb11403f9209855525a25d57Steve Block return; 145cad810f21b803229eb11403f9209855525a25d57Steve Block 146ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (m_waitToDump && !InjectedBundle::shared().topLoadingFrame()) 147e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke InjectedBundle::shared().page()->dump(); 148ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 149e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke m_waitToDump = false; 150e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 151e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 152e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkeunsigned LayoutTestController::numberOfActiveAnimations() const 153e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 1540617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // FIXME: Is it OK this works only for the main frame? 1550617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage? 156e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 157e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return WKBundleFrameGetNumberOfActiveAnimations(mainFrame); 158e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 159e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 160e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkebool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) 161e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 1620617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // FIXME: Is it OK this works only for the main frame? 1630617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage? 1640617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 1650617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return WKBundleFramePauseAnimationOnElementWithId(mainFrame, toWK(animationName).get(), toWK(elementId).get(), time); 1660617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 167e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 16828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid LayoutTestController::suspendAnimations() 16928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 17028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 17128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu WKBundleFrameSuspendAnimations(mainFrame); 17228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 17328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 17428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid LayoutTestController::resumeAnimations() 17528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 17628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 17728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu WKBundleFrameResumeAnimations(mainFrame); 17828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 17928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 180e14391e94c850b8bd03680c23b38978db68687a8John ReckJSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const 181e14391e94c850b8bd03680c23b38978db68687a8John Reck{ 182e14391e94c850b8bd03680c23b38978db68687a8John Reck WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 183e14391e94c850b8bd03680c23b38978db68687a8John Reck WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyLayerTreeAsText(mainFrame)); 184e14391e94c850b8bd03680c23b38978db68687a8John Reck return toJS(text); 185e14391e94c850b8bd03680c23b38978db68687a8John Reck} 186e14391e94c850b8bd03680c23b38978db68687a8John Reck 1875ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames) 1885ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen{ 1895ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen WKRetainPtr<WKStringRef> sourceWK = toWK(source); 1905ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld()); 1915ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 192f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch WKBundleAddUserScript(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0, 1935ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd), 1945ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly)); 1955ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen} 1965ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 1975ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames) 1985ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen{ 1995ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen WKRetainPtr<WKStringRef> sourceWK = toWK(source); 2005ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld()); 2015ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 202f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch WKBundleAddUserStyleSheet(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0, 2035ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly)); 2045ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen} 2055ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 2060617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenvoid LayoutTestController::keepWebHistory() 2070617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 208dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch WKBundleSetShouldTrackVisitedLinks(InjectedBundle::shared().bundle(), true); 2090617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 2100617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 2110617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenJSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSValueRef element) 2120617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 2130617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // FIXME: Is it OK this works only for the main frame? 214e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 2150617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); 2160617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!JSValueIsObject(context, element)) 2170617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return JSValueMakeUndefined(context); 2180617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSValueRef value = WKBundleFrameGetComputedStyleIncludingVisitedInfo(mainFrame, const_cast<JSObjectRef>(element)); 2190617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!value) 2200617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return JSValueMakeUndefined(context); 2210617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return value; 2220617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 2230617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 2240617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenJSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef elementId) 2250617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 2260617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 2270617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSObjectRef element = getElementById(mainFrame, elementId); 2280617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!element) 2290617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 2300617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKRetainPtr<WKStringRef> value(AdoptWK, WKBundleFrameCopyCounterValue(mainFrame, const_cast<JSObjectRef>(element))); 2310617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return toJS(value); 2320617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 2330617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 2340617145a89917ae7735fe1c9538688ab9a577df5Kristian MonsenJSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSValueRef element) 2350617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 2360617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 2370617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); 2380617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (!element || !JSValueIsObject(context, element)) 2390617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 2400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyMarkerText(mainFrame, const_cast<JSObjectRef>(element))); 2410617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (WKStringIsEmpty(text.get())) 2420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return 0; 2430617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return toJS(text); 2440617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 2450617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 2460617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenvoid LayoutTestController::execCommand(JSStringRef name, JSStringRef argument) 2470617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 2480617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen WKBundlePageExecuteEditingCommand(InjectedBundle::shared().page()->page(), toWK(name).get(), toWK(argument).get()); 2490617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen} 2500617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 251f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochbool LayoutTestController::findString(JSStringRef target, JSValueRef optionsArrayAsValue) 252f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{ 253f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch WKFindOptions options = 0; 254f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 255f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 256f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); 257f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); 258f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0); 259f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); 260f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (!JSValueIsNumber(context, lengthValue)) 261f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return false; 262f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 263f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); 264f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch for (size_t i = 0; i < length; ++i) { 265f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); 266f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (!JSValueIsString(context, value)) 267f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch continue; 268f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 269f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); 270f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 271f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive")) 272f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch options |= kWKFindOptionsCaseInsensitive; 273f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts")) 274f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch options |= kWKFindOptionsAtWordStarts; 275f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart")) 276f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch options |= kWKFindOptionsTreatMedialCapitalAsWordStart; 277f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards")) 278f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch options |= kWKFindOptionsBackwards; 279f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround")) 280f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch options |= kWKFindOptionsWrapAround; 281f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) { 282f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // FIXME: No kWKFindOptionsStartInSelection. 283f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 284f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 285f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 286f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return WKBundlePageFindString(InjectedBundle::shared().page()->page(), toWK(target).get(), options); 287f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch} 288f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 2890617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenbool LayoutTestController::isCommandEnabled(JSStringRef name) 2900617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{ 2910617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get()); 292e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 293e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 294db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid LayoutTestController::setCanOpenWindows(bool) 295db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{ 296db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block // It's not clear if or why any tests require opening windows be forbidden. 297db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block // For now, just ignore this setting, and if we find later it's needed we can add it. 298db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block} 299db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 3005ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsenvoid LayoutTestController::setXSSAuditorEnabled(bool enabled) 3015ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen{ 302f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch WKBundleOverrideXSSAuditorEnabledForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), true); 3035ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen} 3045ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 3052bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) 3062bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 3072bde8e466a4451c7319e3a072d118917957d6554Steve Block WKBundleOverrideAllowUniversalAccessFromFileURLsForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); 3082bde8e466a4451c7319e3a072d118917957d6554Steve Block} 3092bde8e466a4451c7319e3a072d118917957d6554Steve Block 310db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockunsigned LayoutTestController::windowCount() 311db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{ 312db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block return InjectedBundle::shared().pageCount(); 313db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block} 314db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 315e14391e94c850b8bd03680c23b38978db68687a8John Reckvoid LayoutTestController::clearBackForwardList() 316e14391e94c850b8bd03680c23b38978db68687a8John Reck{ 317e14391e94c850b8bd03680c23b38978db68687a8John Reck WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page())); 318e14391e94c850b8bd03680c23b38978db68687a8John Reck} 319e14391e94c850b8bd03680c23b38978db68687a8John Reck 320ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block// Object Creation 321ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 322ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) 323ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block{ 3240617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen setProperty(context, windowObject, "layoutTestController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); 325ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block} 326ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 3272fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid LayoutTestController::showWebInspector() 3282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 3292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::shared().page()->page())); 3302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 3312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3322fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid LayoutTestController::closeWebInspector() 3332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 3342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::shared().page()->page())); 3352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 3362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3372fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid LayoutTestController::evaluateInWebInspector(long callID, JSStringRef script) 3382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 3392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block WKRetainPtr<WKStringRef> scriptWK = toWK(script); 3402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), callID, scriptWK.get()); 3412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 3422fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3432fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid LayoutTestController::setTimelineProfilingEnabled(bool enabled) 3442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 3452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block WKBundleInspectorSetPageProfilingEnabled(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), enabled); 3462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 3472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 348ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochtypedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap; 349ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochstatic WorldMap& worldMap() 350ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{ 351ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch static WorldMap& map = *new WorldMap; 352ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return map; 353ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch} 354ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 355ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochunsigned LayoutTestController::worldIDForWorld(WKBundleScriptWorldRef world) 356ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{ 357ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch WorldMap::const_iterator end = worldMap().end(); 358ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) { 359ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (it->second == world) 360ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return it->first; 361ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 362ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 363ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return 0; 364ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch} 365ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 366ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochvoid LayoutTestController::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script) 367ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{ 368ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world 369ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // that is created once and cached forever. 370ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch WKRetainPtr<WKBundleScriptWorldRef> world; 371ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!worldID) 372ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch world.adopt(WKBundleScriptWorldCreateWorld()); 373ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch else { 374ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, 0).first->second; 375ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!worldSlot) 376ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch worldSlot.adopt(WKBundleScriptWorldCreateWorld()); 377ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch world = worldSlot; 378ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 379ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 380ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context); 381ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!frame) 382ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch frame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); 383ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 384ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get()); 385ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch JSEvaluateScript(jsContext, script, 0, 0, 0, 0); 386ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch} 387ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 3882fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid LayoutTestController::setPOSIXLocale(JSStringRef locale) 3892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 3902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block char localeBuf[32]; 3912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf)); 3922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block setlocale(LC_ALL, localeBuf); 3932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 3942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 395ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block} // namespace WTR 396