<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeBasePch.h"

#ifdef ENABLE_JS_ETW
#include "Core/EtwTraceCore.h"
#include "Base/EtwTrace.h"

using namespace Js;

#ifndef ENABLE_JS_LTTNG
//
// This C style callback is invoked by ETW when a trace session is started/stopped
// by an ETW controller for the Jscript and MSHTML providers.
//

void EtwCallbackApi::OnSessionChange(ULONG controlCode, PVOID callbackContext)
{
    PMCGEN_TRACE_CONTEXT context = (PMCGEN_TRACE_CONTEXT)callbackContext;

    // A manifest based provider can be enabled to multiple event tracing sessions
    // As long as there is at least 1 enabled session, isEnabled will be TRUE
    // We only care about Jscript events.
    if(context->RegistrationHandle == Microsoft_JScriptHandle)
    {
        switch(controlCode)
        {
        case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
        case EVENT_CONTROL_CODE_CAPTURE_STATE:
            if(McGenLevelKeywordEnabled(context,
                TRACE_LEVEL_INFORMATION,
                JSCRIPT_RUNDOWNSTART_KEYWORD))
            {
                EtwTrace::PerformRundown(/*start*/ true);
            }

            if(McGenLevelKeywordEnabled(context,
                TRACE_LEVEL_INFORMATION,
                JSCRIPT_RUNDOWNEND_KEYWORD))
            {
                EtwTrace::PerformRundown(/*start*/ false);
            }
            break;
        case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
            break; // Do Nothing
        }
    }
}
#endif

//
// Registers the ETW provider - this is usually done on Jscript DLL load
// After registration, we will receive callbacks when ETW tracing is enabled/disabled.
//
void EtwTrace::Register()
{
#ifndef ENABLE_JS_LTTNG
    EtwTraceCore::Register();
#endif

#ifdef TEST_ETW_EVENTS
    TestEtwEventSink::Load();
#endif
}

//
// Unregister to ensure we do not get callbacks.
//
void EtwTrace::UnRegister()
{
#ifndef ENABLE_JS_LTTNG
    EtwTraceCore::UnRegister();
#endif

#ifdef TEST_ETW_EVENTS
    TestEtwEventSink::Unload();
#endif
}

//
// Enumerate through all the script contexts in the process and log events
// for each function loaded. Depending on the argument, start or end events are logged.
// In particular, a rundown is needed for the 'Attach' scenario of profiling.
//
void EtwTrace::PerformRundown(bool start)
{
    // Lock threadContext list during etw rundown
    AutoCriticalSection autoThreadContextCs(ThreadContext::GetCriticalSection());

    ThreadContext * threadContext = ThreadContext::GetThreadContextList();
    if(start)
    {
        JS_ETW(EventWriteDCStartInit());
    }
    else
    {
        JS_ETW(EventWriteDCEndInit());
    }

    while(threadContext != nullptr)
    {
        // Take etw rundown lock on this thread context
        AutoCriticalSection autoEtwRundownCs(threadContext->GetFunctionBodyLock());

        ScriptContext* scriptContext = threadContext->GetScriptContextList();
        while(scriptContext != NULL)
        {
            if(scriptContext->IsClosed())
            {
                scriptContext = scriptContext->next;
                continue;
            }
            if(start)
            {
                JS_ETW(EventWriteScriptContextDCStart(scriptContext));

                if(scriptContext->GetSourceContextInfoMap() != nullptr)
                {
                    scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
                    {
                        if (sourceContext != Constants::NoHostSourceContext)
                        {
                            JS_ETW(LogSourceEvent(EventWriteSourceDCStart,
                                sourceContext,
                                scriptContext,
                                /* sourceFlags*/ 0,
                                sourceContextInfo->url));
                        }
                    });
                }
            }
            else
            {
                JS_ETW(EventWriteScriptContextDCEnd(scriptContext));

                if(scriptContext->GetSourceContextInfoMap() != nullptr)
                {
                    scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
                    {
                        if (sourceContext != Constants::NoHostSourceContext)
                        {
                            JS_ETW(LogSourceEvent(EventWriteSourceDCEnd,
                                sourceContext,
                                scriptContext,
                                /* sourceFlags*/ 0,
                                sourceContextInfo->url));
                        }
                    });
                }
            }

            scriptContext->MapFunction([&start] (FunctionBody* body)
            {
#if DYNAMIC_INTERPRETER_THUNK
                if(body->HasInterpreterThunkGenerated())
                {
                    if(start)
                    {
                        LogMethodInterpretedThunkEvent(EventWriteMethodDCStart, body);
                    }
                    else
                    {
                        LogMethodInterpretedThunkEvent(EventWriteMethodDCEnd, body);
                    }
                }
#endif

#if ENABLE_NATIVE_CODEGEN
                body->MapEntryPoints([&](int index, FunctionEntryPointInfo * entryPoint)
                {
                    if(entryPoint->IsCodeGenDone())
                    {
                        if (start)
                        {
                            LogMethodNativeEvent(EventWriteMethodDCStart, body, entryPoint);
                        }
                        else
                        {
                            LogMethodNativeEvent(EventWriteMethodDCEnd, body, entryPoint);
                        }
                    }
                });

                // the functionBody may have not have bytecode generated yet before registering to utf8SourceInfo
                // accessing MapLoopHeaders in background thread can causes the functionBody counters locked for updating
                // and cause assertion when bytecode generation is done and updating bytecodeCount counter on functionBody
                // so check if the functionBody has done loopbody codegen in advance to not call into Map function in case
                // loopbody codegen is not done yet
                if (body->GetHasDoneLoopBodyCodeGen())
                {
                    body->MapLoopHeadersWithLock([&](uint loopNumber, LoopHeader* header)
                    {
                        header->MapEntryPoints([&](int index, LoopEntryPointInfo * entryPoint)
                        {
                            if (entryPoint->IsCodeGenDone())
                            {
                                if (start)
                                {
                                    LogLoopBodyEvent(EventWriteMethodDCStart, body, entryPoint, ((uint16)body->GetLoopNumberWithLock(header)));
                                }
                                else
                                {
                                    LogLoopBodyEvent(EventWriteMethodDCEnd, body, entryPoint, ((uint16)body->GetLoopNumberWithLock(header)));
                                }
                            }
                        });
                    });
                }
#endif
            });

            scriptContext = scriptContext->next;
        }
#ifdef NTBUILD
        if (EventEnabledJSCRIPT_HOSTING_CEO_START())
        {
            threadContext->EtwLogPropertyIdList();
        }
#endif

        threadContext = threadContext->Next();
    }
    if(start)
    {
        JS_ETW(EventWriteDCStartComplete());
    }
    else
    {
        JS_ETW(EventWriteDCEndComplete());
    }
}

//
// Returns an ID for the source file of the function.
//
DWORD_PTR EtwTrace::GetSourceId(FunctionBody* body)
{
    DWORD_PTR sourceId = body->GetHostSourceContext();

    // For dynamic scripts - use fixed source ID of -1.
    // TODO: Find a way to generate unique ID for dynamic scripts.
    if(sourceId == Js::Constants::NoHostSourceContext)
    {
        sourceId = (DWORD_PTR)-1;
    }
    return sourceId;
}

//
// Returns an ID to identify the function.
//
uint EtwTrace::GetFunctionId(FunctionProxy* body)
{
    return body->GetFunctionNumber();
}

void EtwTrace::LogSourceUnloadEvents(ScriptContext* scriptContext)
{
    if(scriptContext->GetSourceContextInfoMap() != nullptr)
    {
        scriptContext->GetSourceContextInfoMap()->Map( [&] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
        {
            if(sourceContext != Constants::NoHostSourceContext)
            {
                JS_ETW(LogSourceEvent(EventWriteSourceUnload,
                    sourceContext,
                    scriptContext,
                    /* sourceFlags*/ 0,
                    sourceContextInfo->url));
            }
        });
    }

    JS_ETW(EventWriteScriptContextUnload(scriptContext));
}

void EtwTrace::LogMethodInterpreterThunkLoadEvent(FunctionBody* body)
{
#if DYNAMIC_INTERPRETER_THUNK
    LogMethodInterpretedThunkEvent(EventWriteMethodLoad, body);
#else
    Assert(false); // Caller should not be enabled if Dynamic Interpreter Thunks are disabled
#endif
}

void EtwTrace::LogMethodNativeLoadEvent(FunctionBody* body, FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
    LogMethodNativeEvent(EventWriteMethodLoad, body, entryPoint);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogLoopBodyLoadEvent(FunctionBody* body, LoopEntryPointInfo* entryPoint, uint16 loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
    LogLoopBodyEvent(EventWriteMethodLoad, body, entryPoint, loopNumber);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogMethodInterpreterThunkUnloadEvent(FunctionBody* body)
{
#if DYNAMIC_INTERPRETER_THUNK
    LogMethodInterpretedThunkEvent(EventWriteMethodUnload, body);
#else
Assert(false); // Caller should not be enabled if dynamic interpreter thunks are disabled
#endif
}

void EtwTrace::LogMethodNativeUnloadEvent(FunctionBody* body, FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
    LogMethodNativeEvent(EventWriteMethodUnload, body, entryPoint);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogLoopBodyUnloadEvent(FunctionBody* body, LoopEntryPointInfo* entryPoint, uint loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
    LogLoopBodyEvent(EventWriteMethodUnload, body, entryPoint, loopNumber);
#else
Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

//
// Logs the runtime script context load event
//
void EtwTrace::LogScriptContextLoadEvent(ScriptContext* scriptContext)
{
    JS_ETW(EventWriteScriptContextLoad(
        scriptContext));
}

//
// Logs the runtime source module load event.
//
void EtwTrace::LogSourceModuleLoadEvent(ScriptContext* scriptContext, DWORD_PTR sourceContext, _In_z_ const char16* url)
{
    AssertMsg(sourceContext != Constants::NoHostSourceContext, "We should not be logged this if there is no source code available");

    JS_ETW(LogSourceEvent(EventWriteSourceLoad,
        sourceContext,
        scriptContext,
        /* sourceFlags*/ 0,
        url));
}

//
// This emulates the logic used by the F12 profiler to give names to functions
//
const char16* EtwTrace::GetFunctionName(FunctionBody* body)
{
    return body->GetExternalDisplayName();
}

size_t EtwTrace::GetLoopBodyName(_In_ FunctionBody* body, _In_ LoopHeader* loopHeader, _Out_writes_opt_z_(size) char16* nameBuffer, _In_ size_t size)
{
    return body->GetLoopBodyName(body->GetLoopNumber(loopHeader), nameBuffer, size);
}

_Success_(return == 0)
size_t EtwTrace::GetSimpleJitFunctionName(
    Js::FunctionBody *const body,
    _Out_writes_opt_z_(nameCharCapacity) char16 *const name,
    const size_t nameCharCapacity)
{
    Assert(body);
    Assert(name);
    Assert(nameCharCapacity != 0);

    const char16 *const suffix = _u("Simple");
    const size_t suffixCharLength = _countof(_u("Simple")) - 1;

    const char16 *const functionName = GetFunctionName(body);
    const size_t functionNameCharLength = wcslen(functionName);
    const size_t requiredCharCapacity = functionNameCharLength + suffixCharLength + 1;
    if(requiredCharCapacity > nameCharCapacity || name == NULL)
    {
        return requiredCharCapacity;
    }

    wcscpy_s(name, nameCharCapacity, functionName);
    wcscpy_s(&name[functionNameCharLength], nameCharCapacity - functionNameCharLength, suffix);
    return 0;
}

#endif
<commit_msg>[1.11>master] [1.10>1.11] [MERGE #5919 @pleath] Handle non-null-terminated function name in ETW<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeBasePch.h"

#ifdef ENABLE_JS_ETW
#include "Core/EtwTraceCore.h"
#include "Base/EtwTrace.h"

using namespace Js;

#ifndef ENABLE_JS_LTTNG
//
// This C style callback is invoked by ETW when a trace session is started/stopped
// by an ETW controller for the Jscript and MSHTML providers.
//

void EtwCallbackApi::OnSessionChange(ULONG controlCode, PVOID callbackContext)
{
    PMCGEN_TRACE_CONTEXT context = (PMCGEN_TRACE_CONTEXT)callbackContext;

    // A manifest based provider can be enabled to multiple event tracing sessions
    // As long as there is at least 1 enabled session, isEnabled will be TRUE
    // We only care about Jscript events.
    if(context->RegistrationHandle == Microsoft_JScriptHandle)
    {
        switch(controlCode)
        {
        case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
        case EVENT_CONTROL_CODE_CAPTURE_STATE:
            if(McGenLevelKeywordEnabled(context,
                TRACE_LEVEL_INFORMATION,
                JSCRIPT_RUNDOWNSTART_KEYWORD))
            {
                EtwTrace::PerformRundown(/*start*/ true);
            }

            if(McGenLevelKeywordEnabled(context,
                TRACE_LEVEL_INFORMATION,
                JSCRIPT_RUNDOWNEND_KEYWORD))
            {
                EtwTrace::PerformRundown(/*start*/ false);
            }
            break;
        case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
            break; // Do Nothing
        }
    }
}
#endif

//
// Registers the ETW provider - this is usually done on Jscript DLL load
// After registration, we will receive callbacks when ETW tracing is enabled/disabled.
//
void EtwTrace::Register()
{
#ifndef ENABLE_JS_LTTNG
    EtwTraceCore::Register();
#endif

#ifdef TEST_ETW_EVENTS
    TestEtwEventSink::Load();
#endif
}

//
// Unregister to ensure we do not get callbacks.
//
void EtwTrace::UnRegister()
{
#ifndef ENABLE_JS_LTTNG
    EtwTraceCore::UnRegister();
#endif

#ifdef TEST_ETW_EVENTS
    TestEtwEventSink::Unload();
#endif
}

//
// Enumerate through all the script contexts in the process and log events
// for each function loaded. Depending on the argument, start or end events are logged.
// In particular, a rundown is needed for the 'Attach' scenario of profiling.
//
void EtwTrace::PerformRundown(bool start)
{
    // Lock threadContext list during etw rundown
    AutoCriticalSection autoThreadContextCs(ThreadContext::GetCriticalSection());

    ThreadContext * threadContext = ThreadContext::GetThreadContextList();
    if(start)
    {
        JS_ETW(EventWriteDCStartInit());
    }
    else
    {
        JS_ETW(EventWriteDCEndInit());
    }

    while(threadContext != nullptr)
    {
        // Take etw rundown lock on this thread context
        AutoCriticalSection autoEtwRundownCs(threadContext->GetFunctionBodyLock());

        ScriptContext* scriptContext = threadContext->GetScriptContextList();
        while(scriptContext != NULL)
        {
            if(scriptContext->IsClosed())
            {
                scriptContext = scriptContext->next;
                continue;
            }
            if(start)
            {
                JS_ETW(EventWriteScriptContextDCStart(scriptContext));

                if(scriptContext->GetSourceContextInfoMap() != nullptr)
                {
                    scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
                    {
                        if (sourceContext != Constants::NoHostSourceContext)
                        {
                            JS_ETW(LogSourceEvent(EventWriteSourceDCStart,
                                sourceContext,
                                scriptContext,
                                /* sourceFlags*/ 0,
                                sourceContextInfo->url));
                        }
                    });
                }
            }
            else
            {
                JS_ETW(EventWriteScriptContextDCEnd(scriptContext));

                if(scriptContext->GetSourceContextInfoMap() != nullptr)
                {
                    scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
                    {
                        if (sourceContext != Constants::NoHostSourceContext)
                        {
                            JS_ETW(LogSourceEvent(EventWriteSourceDCEnd,
                                sourceContext,
                                scriptContext,
                                /* sourceFlags*/ 0,
                                sourceContextInfo->url));
                        }
                    });
                }
            }

            scriptContext->MapFunction([&start] (FunctionBody* body)
            {
#if DYNAMIC_INTERPRETER_THUNK
                if(body->HasInterpreterThunkGenerated())
                {
                    if(start)
                    {
                        LogMethodInterpretedThunkEvent(EventWriteMethodDCStart, body);
                    }
                    else
                    {
                        LogMethodInterpretedThunkEvent(EventWriteMethodDCEnd, body);
                    }
                }
#endif

#if ENABLE_NATIVE_CODEGEN
                body->MapEntryPoints([&](int index, FunctionEntryPointInfo * entryPoint)
                {
                    if(entryPoint->IsCodeGenDone())
                    {
                        if (start)
                        {
                            LogMethodNativeEvent(EventWriteMethodDCStart, body, entryPoint);
                        }
                        else
                        {
                            LogMethodNativeEvent(EventWriteMethodDCEnd, body, entryPoint);
                        }
                    }
                });

                // the functionBody may have not have bytecode generated yet before registering to utf8SourceInfo
                // accessing MapLoopHeaders in background thread can causes the functionBody counters locked for updating
                // and cause assertion when bytecode generation is done and updating bytecodeCount counter on functionBody
                // so check if the functionBody has done loopbody codegen in advance to not call into Map function in case
                // loopbody codegen is not done yet
                if (body->GetHasDoneLoopBodyCodeGen())
                {
                    body->MapLoopHeadersWithLock([&](uint loopNumber, LoopHeader* header)
                    {
                        header->MapEntryPoints([&](int index, LoopEntryPointInfo * entryPoint)
                        {
                            if (entryPoint->IsCodeGenDone())
                            {
                                if (start)
                                {
                                    LogLoopBodyEvent(EventWriteMethodDCStart, body, entryPoint, ((uint16)body->GetLoopNumberWithLock(header)));
                                }
                                else
                                {
                                    LogLoopBodyEvent(EventWriteMethodDCEnd, body, entryPoint, ((uint16)body->GetLoopNumberWithLock(header)));
                                }
                            }
                        });
                    });
                }
#endif
            });

            scriptContext = scriptContext->next;
        }
#ifdef NTBUILD
        if (EventEnabledJSCRIPT_HOSTING_CEO_START())
        {
            threadContext->EtwLogPropertyIdList();
        }
#endif

        threadContext = threadContext->Next();
    }
    if(start)
    {
        JS_ETW(EventWriteDCStartComplete());
    }
    else
    {
        JS_ETW(EventWriteDCEndComplete());
    }
}

//
// Returns an ID for the source file of the function.
//
DWORD_PTR EtwTrace::GetSourceId(FunctionBody* body)
{
    DWORD_PTR sourceId = body->GetHostSourceContext();

    // For dynamic scripts - use fixed source ID of -1.
    // TODO: Find a way to generate unique ID for dynamic scripts.
    if(sourceId == Js::Constants::NoHostSourceContext)
    {
        sourceId = (DWORD_PTR)-1;
    }
    return sourceId;
}

//
// Returns an ID to identify the function.
//
uint EtwTrace::GetFunctionId(FunctionProxy* body)
{
    return body->GetFunctionNumber();
}

void EtwTrace::LogSourceUnloadEvents(ScriptContext* scriptContext)
{
    if(scriptContext->GetSourceContextInfoMap() != nullptr)
    {
        scriptContext->GetSourceContextInfoMap()->Map( [&] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo)
        {
            if(sourceContext != Constants::NoHostSourceContext)
            {
                JS_ETW(LogSourceEvent(EventWriteSourceUnload,
                    sourceContext,
                    scriptContext,
                    /* sourceFlags*/ 0,
                    sourceContextInfo->url));
            }
        });
    }

    JS_ETW(EventWriteScriptContextUnload(scriptContext));
}

void EtwTrace::LogMethodInterpreterThunkLoadEvent(FunctionBody* body)
{
#if DYNAMIC_INTERPRETER_THUNK
    LogMethodInterpretedThunkEvent(EventWriteMethodLoad, body);
#else
    Assert(false); // Caller should not be enabled if Dynamic Interpreter Thunks are disabled
#endif
}

void EtwTrace::LogMethodNativeLoadEvent(FunctionBody* body, FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
    LogMethodNativeEvent(EventWriteMethodLoad, body, entryPoint);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogLoopBodyLoadEvent(FunctionBody* body, LoopEntryPointInfo* entryPoint, uint16 loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
    LogLoopBodyEvent(EventWriteMethodLoad, body, entryPoint, loopNumber);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogMethodInterpreterThunkUnloadEvent(FunctionBody* body)
{
#if DYNAMIC_INTERPRETER_THUNK
    LogMethodInterpretedThunkEvent(EventWriteMethodUnload, body);
#else
Assert(false); // Caller should not be enabled if dynamic interpreter thunks are disabled
#endif
}

void EtwTrace::LogMethodNativeUnloadEvent(FunctionBody* body, FunctionEntryPointInfo* entryPoint)
{
#if ENABLE_NATIVE_CODEGEN
    LogMethodNativeEvent(EventWriteMethodUnload, body, entryPoint);
#else
    Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

void EtwTrace::LogLoopBodyUnloadEvent(FunctionBody* body, LoopEntryPointInfo* entryPoint, uint loopNumber)
{
#if ENABLE_NATIVE_CODEGEN
    LogLoopBodyEvent(EventWriteMethodUnload, body, entryPoint, loopNumber);
#else
Assert(false); // Caller should not be enabled if JIT is disabled
#endif
}

//
// Logs the runtime script context load event
//
void EtwTrace::LogScriptContextLoadEvent(ScriptContext* scriptContext)
{
    JS_ETW(EventWriteScriptContextLoad(
        scriptContext));
}

//
// Logs the runtime source module load event.
//
void EtwTrace::LogSourceModuleLoadEvent(ScriptContext* scriptContext, DWORD_PTR sourceContext, _In_z_ const char16* url)
{
    AssertMsg(sourceContext != Constants::NoHostSourceContext, "We should not be logged this if there is no source code available");

    JS_ETW(LogSourceEvent(EventWriteSourceLoad,
        sourceContext,
        scriptContext,
        /* sourceFlags*/ 0,
        url));
}

//
// This emulates the logic used by the F12 profiler to give names to functions
//
const char16* EtwTrace::GetFunctionName(FunctionBody* body)
{
    return body->GetExternalDisplayName();
}

size_t EtwTrace::GetLoopBodyName(_In_ FunctionBody* body, _In_ LoopHeader* loopHeader, _Out_writes_opt_z_(size) char16* nameBuffer, _In_ size_t size)
{
    return body->GetLoopBodyName(body->GetLoopNumber(loopHeader), nameBuffer, size);
}

_Success_(return == 0)
size_t EtwTrace::GetSimpleJitFunctionName(
    Js::FunctionBody *const body,
    _Out_writes_opt_z_(nameCharCapacity) char16 *const name,
    const size_t nameCharCapacity)
{
    Assert(body);
    Assert(name);
    Assert(nameCharCapacity != 0);

    const char16 *const suffix = _u("Simple");
    const size_t suffixCharLength = _countof(_u("Simple")) - 1;

    const char16 *const functionName = GetFunctionName(body);
    const size_t functionNameCharLength = body->GetDisplayNameLength();
    const size_t requiredCharCapacity = functionNameCharLength + suffixCharLength + 1;
    if(requiredCharCapacity > nameCharCapacity || name == NULL)
    {
        return requiredCharCapacity;
    }

    wcscpy_s(name, nameCharCapacity, functionName);
    wcscpy_s(&name[functionNameCharLength], nameCharCapacity - functionNameCharLength, suffix);
    return 0;
}

#endif
<|endoftext|>


<commit_before>#ifndef UTIL_VARIANT_HPP
#define UTIL_VARIANT_HPP

#include <utility>
#include <typeinfo>
#include <type_traits>
#include <algorithm> // std::move/swap
#include <stdexcept> // runtime_error
#include <new> // operator new
#include <cstddef> // size_t

#ifdef NDEBUG
 #define VARIANT_INLINE inline __attribute__((always_inline))
#else
 #define VARIANT_INLINE __attribute__((noinline))
#endif

namespace util {

namespace detail {

static constexpr std::size_t invalid_value = std::size_t(-1);

template <typename T, typename...Types>
struct type_traits;

template <typename T, typename First, typename...Types>
struct type_traits<T, First, Types...>
{
    static constexpr std::size_t id = std::is_same<T, First>::value ? sizeof...(Types) : type_traits<T, Types...>::id;
};

template <typename T>
struct type_traits<T>
{
    static constexpr std::size_t id = invalid_value;
};

template <typename T, typename...Types>
struct is_valid_type;

template <typename T, typename First, typename... Types>
struct is_valid_type<T,First,Types...>
{
    static constexpr bool value = std::is_same<T,First>::value
        || is_valid_type<T,Types...>::value;
};

template <typename T>
struct is_valid_type<T> : std::false_type {};

}

template <std::size_t arg1, std::size_t ... others>
struct static_max;

template <std::size_t arg>
struct static_max<arg>
{
    static const std::size_t value = arg;
};

template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
struct static_max<arg1, arg2, others...>
{
    static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
        static_max<arg2, others...>::value;
};

template<typename... Types>
struct variant_helper;

template<typename T, typename... Types>
struct variant_helper<T, Types...>
{
    VARIANT_INLINE static void destroy(std::size_t id, void * data)
    {
        if (id == sizeof...(Types))
        {
            reinterpret_cast<T*>(data)->~T();
        }
        else
        {
            variant_helper<Types...>::destroy(id, data);
        }
    }

    VARIANT_INLINE static void move(std::size_t old_t, void * old_v, void * new_v)
    {
        if (old_t == sizeof...(Types))
        {
            new (new_v) T(std::move(*reinterpret_cast<T*>(old_v)));
        }
        else
        {
            variant_helper<Types...>::move(old_t, old_v, new_v);
        }
    }

    VARIANT_INLINE static void copy(std::size_t old_t, const void * old_v, void * new_v)
    {
        if (old_t == sizeof...(Types))
        {
            new (new_v) T(*reinterpret_cast<const T*>(old_v));
        }
        else
        {
            variant_helper<Types...>::copy(old_t, old_v, new_v);
        }
    }
};

template<> struct variant_helper<>
{
    VARIANT_INLINE static void destroy(std::size_t, void *) {}
    VARIANT_INLINE static void move(std::size_t, void *, void *) {}
    VARIANT_INLINE static void copy(std::size_t, const void *, void *) {}
};

namespace detail {

template <typename F, typename V, typename...Types>
struct dispatcher;

template <typename F, typename V, typename T, typename...Types>
struct dispatcher<F,V,T,Types...>
{
    typedef typename std::result_of<F(V const&)>::type result_type;
    VARIANT_INLINE static result_type apply(V const& v, F f)
    {
        if (v.get_type_id() == sizeof...(Types))
        {
            return f(v. template get<T>());
        }
        else
        {
            return dispatcher<F,V,Types...>::apply(v, f);
        }
    }
};

template<typename F,typename V>
struct dispatcher<F,V>
{
    typedef typename std::result_of<F(V const&)>::type result_type;
    VARIANT_INLINE static result_type apply(V const&, F)
    {
        throw std::runtime_error("dispatch: FAIL");
    }
};

} // detail

template<typename... Types>
struct variant
{
private:

    static const std::size_t data_size = static_max<sizeof(Types)...>::value;
    static const std::size_t data_align = static_max<alignof(Types)...>::value;

    using data_t = typename std::aligned_storage<data_size, data_align>::type;

    using helper_t = variant_helper<Types...>;

    std::size_t type_id;
    data_t data;

public:

    VARIANT_INLINE variant()
        : type_id(detail::invalid_value) {}

    template <typename T>
    VARIANT_INLINE explicit variant(T const& val) noexcept
        : type_id(detail::type_traits<T, Types...>::id)
    {
        static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
        new (&data) T(val);
    }

    template <typename T>
    VARIANT_INLINE variant(T && val) noexcept
        : type_id(detail::type_traits<T,Types...>::id)
    {
        static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
        new (&data) T(std::forward<T>(val)); // nothrow
    }

    VARIANT_INLINE variant(variant<Types...> const& old)
        : type_id(old.type_id)
    {
        helper_t::copy(old.type_id, &old.data, &data);
    }

    VARIANT_INLINE variant(variant<Types...>&& old) noexcept
        : type_id(old.type_id)
    {
        helper_t::move(old.type_id, &old.data, &data);
    }

    VARIANT_INLINE variant<Types...>& operator= (variant<Types...> old)
    {
        std::swap(type_id, old.type_id);
        std::swap(data, old.data);
        return *this;
    }

    template<typename T>
    VARIANT_INLINE void is()
    {
        return (type_id == detail::type_traits<T, Types...>::id);
    }

    VARIANT_INLINE void valid()
    {
        return (type_id != detail::invalid_value);
    }

    template<typename T, typename... Args>
    VARIANT_INLINE void set(Args&&... args)
    {
        helper_t::destroy(type_id, &data);
        new (&data) T(std::forward<Args>(args)...);
        type_id = detail::type_traits<T,Types...>::id;
    }

    template<typename T>
    VARIANT_INLINE T& get()
    {
        if (type_id == detail::type_traits<T,Types...>::id)
        {
            return *reinterpret_cast<T*>(&data);
        }
        else
        {
            throw std::runtime_error("in get()");
        }
    }

    template<typename T>
    VARIANT_INLINE T const& get() const
    {
        if (type_id == detail::type_traits<T,Types...>::id)
        {
            return *reinterpret_cast<T const*>(&data);
        }
        else
        {
            throw std::runtime_error("in get()");
        }
    }

    VARIANT_INLINE std::size_t get_type_id() const
    {
        return type_id;
    }

    // visitor
    template <typename F, typename V>
    typename std::result_of<F(V const&)>::type
    VARIANT_INLINE static visit(V const& v, F f)
    {
        return detail::dispatcher<F, V, Types...>::apply(v, f);
    }

    ~variant() noexcept
    {
        helper_t::destroy(type_id, &data);
    }
};

// unary visitor interface
template <typename V, typename F>
typename std::result_of<F(V const&)>::type
VARIANT_INLINE static apply_visitor(V const& v, F f)
{
    return V::visit(v,f);
}

}

#endif  // UTIL_VARIANT_HPP
<commit_msg>const as const can. also reimplementation of operator= to allow for ADL in swap<commit_after>#ifndef UTIL_VARIANT_HPP
#define UTIL_VARIANT_HPP

#include <utility>
#include <typeinfo>
#include <type_traits>
#include <algorithm> // std::move/swap
#include <stdexcept> // runtime_error
#include <new> // operator new
#include <cstddef> // size_t

#ifdef NDEBUG
 #define VARIANT_INLINE inline __attribute__((always_inline))
#else
 #define VARIANT_INLINE __attribute__((noinline))
#endif

namespace util {

namespace detail {

static constexpr std::size_t invalid_value = std::size_t(-1);

template <typename T, typename...Types>
struct type_traits;

template <typename T, typename First, typename...Types>
struct type_traits<T, First, Types...>
{
    static constexpr std::size_t id = std::is_same<T, First>::value ? sizeof...(Types) : type_traits<T, Types...>::id;
};

template <typename T>
struct type_traits<T>
{
    static constexpr std::size_t id = invalid_value;
};

template <typename T, typename...Types>
struct is_valid_type;

template <typename T, typename First, typename... Types>
struct is_valid_type<T,First,Types...>
{
    static constexpr bool value = std::is_same<T,First>::value
        || is_valid_type<T,Types...>::value;
};

template <typename T>
struct is_valid_type<T> : std::false_type {};

}

template <std::size_t arg1, std::size_t ... others>
struct static_max;

template <std::size_t arg>
struct static_max<arg>
{
    static const std::size_t value = arg;
};

template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
struct static_max<arg1, arg2, others...>
{
    static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
        static_max<arg2, others...>::value;
};

template<typename... Types>
struct variant_helper;

template<typename T, typename... Types>
struct variant_helper<T, Types...>
{
    VARIANT_INLINE static void destroy(std::size_t id, void * data)
    {
        if (id == sizeof...(Types))
        {
            reinterpret_cast<T*>(data)->~T();
        }
        else
        {
            variant_helper<Types...>::destroy(id, data);
        }
    }

    VARIANT_INLINE static void move(const std::size_t old_t, void * old_v, void * new_v)
    {
        if (old_t == sizeof...(Types))
        {
            new (new_v) T(std::move(*reinterpret_cast<T*>(old_v)));
        }
        else
        {
            variant_helper<Types...>::move(old_t, old_v, new_v);
        }
    }

    VARIANT_INLINE static void copy(const std::size_t old_t, const void * old_v, void * new_v)
    {
        if (old_t == sizeof...(Types))
        {
            new (new_v) T(*reinterpret_cast<const T*>(old_v));
        }
        else
        {
            variant_helper<Types...>::copy(old_t, old_v, new_v);
        }
    }
};

template<> struct variant_helper<>
{
    VARIANT_INLINE static void destroy(const std::size_t, void *) {}
    VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
    VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
};

namespace detail {

template <typename F, typename V, typename...Types>
struct dispatcher;

template <typename F, typename V, typename T, typename...Types>
struct dispatcher<F,V,T,Types...>
{
    typedef typename std::result_of<F(V const&)>::type result_type;
    VARIANT_INLINE static result_type apply(V const& v, F f)
    {
        if (v.get_type_id() == sizeof...(Types))
        {
            return f(v. template get<T>());
        }
        else
        {
            return dispatcher<F,V,Types...>::apply(v, f);
        }
    }
};

template<typename F,typename V>
struct dispatcher<F,V>
{
    typedef typename std::result_of<F(V const&)>::type result_type;
    VARIANT_INLINE static result_type apply(V const&, F)
    {
        throw std::runtime_error("dispatch: FAIL");
    }
};

} // detail

template<typename... Types>
struct variant
{
private:

    static const std::size_t data_size = static_max<sizeof(Types)...>::value;
    static const std::size_t data_align = static_max<alignof(Types)...>::value;

    using data_t = typename std::aligned_storage<data_size, data_align>::type;

    using helper_t = variant_helper<Types...>;

    std::size_t type_id;
    data_t data;

public:

    VARIANT_INLINE variant()
        : type_id(detail::invalid_value) {}

    template <typename T>
    VARIANT_INLINE explicit variant(T const& val) noexcept
        : type_id(detail::type_traits<T, Types...>::id)
    {
        static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
        new (&data) T(val);
    }

    template <typename T>
    VARIANT_INLINE variant(T && val) noexcept
        : type_id(detail::type_traits<T,Types...>::id)
    {
        static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
        new (&data) T(std::forward<T>(val)); // nothrow
    }

    VARIANT_INLINE variant(variant<Types...> const& old)
        : type_id(old.type_id)
    {
        helper_t::copy(old.type_id, &old.data, &data);
    }

    VARIANT_INLINE variant(variant<Types...>&& old) noexcept
        : type_id(old.type_id)
    {
        helper_t::move(old.type_id, &old.data, &data);
    }

    friend void swap(variant<Types...> & first, variant<Types...> & second)
    {
        using std::swap; //enable ADL
        swap(first.type_id, second.type_id);
        swap(first.data, second.data);
    }

    VARIANT_INLINE variant<Types...>& operator= (variant<Types...> other)
    {
        swap(*this, other);
        return *this;
    }

    template<typename T>
    VARIANT_INLINE void is() const
    {
        return (type_id == detail::type_traits<T, Types...>::id);
    }

    VARIANT_INLINE void valid() const
    {
        return (type_id != detail::invalid_value);
    }

    template<typename T, typename... Args>
    VARIANT_INLINE void set(Args&&... args)
    {
        helper_t::destroy(type_id, &data);
        new (&data) T(std::forward<Args>(args)...);
        type_id = detail::type_traits<T,Types...>::id;
    }

    template<typename T>
    VARIANT_INLINE T& get()
    {
        if (type_id == detail::type_traits<T,Types...>::id)
        {
            return *reinterpret_cast<T*>(&data);
        }
        else
        {
            throw std::runtime_error("in get()");
        }
    }

    template<typename T>
    VARIANT_INLINE T const& get() const
    {
        if (type_id == detail::type_traits<T,Types...>::id)
        {
            return *reinterpret_cast<T const*>(&data);
        }
        else
        {
            throw std::runtime_error("in get()");
        }
    }

    VARIANT_INLINE std::size_t get_type_id() const
    {
        return type_id;
    }

    // visitor
    template <typename F, typename V>
    typename std::result_of<F(V const&)>::type
    VARIANT_INLINE static visit(V const& v, F f)
    {
        return detail::dispatcher<F, V, Types...>::apply(v, f);
    }

    ~variant() noexcept
    {
        helper_t::destroy(type_id, &data);
    }

};

// unary visitor interface
template <typename V, typename F>
typename std::result_of<F(V const&)>::type
VARIANT_INLINE static apply_visitor(V const& v, F f)
{
    return V::visit(v,f);
}

}

#endif  // UTIL_VARIANT_HPP
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "glproc.hpp"
#include "retrace.hpp"
#include "glretrace.hpp"

using namespace glretrace;

typedef std::map<unsigned long, glws::Drawable *> DrawableMap;
typedef std::map<unsigned long long, glws::Context *> ContextMap;
static DrawableMap drawable_map;
static ContextMap context_map;

static glws::Drawable *
getDrawable(unsigned long drawable_id) {
    if (drawable_id == 0) {
        return NULL;
    }

    DrawableMap::const_iterator it;
    it = drawable_map.find(drawable_id);
    if (it == drawable_map.end()) {
        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
    }

    return it->second;
}

static glws::Context *
getContext(unsigned long long context_ptr) {
    if (context_ptr == 0) {
        return NULL;
    }

    ContextMap::const_iterator it;
    it = context_map.find(context_ptr);
    if (it == context_map.end()) {
        return (context_map[context_ptr] = glws::createContext(visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile));
    }

    return it->second;
}

static void retrace_glXCreateContext(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXCreateContextAttribsARB(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXMakeCurrent(trace::Call &call) {
    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
    glws::Context *new_context = getContext(call.arg(2).toUIntPtr());

    if (new_drawable == drawable && new_context == context) {
        return;
    }

    if (drawable && context) {
        glFlush();
        if (!double_buffer) {
            frame_complete(call);
        }
    }

    bool result = glws::makeCurrent(new_drawable, new_context);

    if (new_drawable && new_context && result) {
        drawable = new_drawable;
        context = new_context;
    } else {
        drawable = NULL;
        context = NULL;
    }
}

static void retrace_glXDestroyContext(trace::Call &call) {
    glws::Context *context = getContext(call.arg(1).toUIntPtr());

    if (!context) {
        return;
    }

    delete context;
}

static void retrace_glXSwapBuffers(trace::Call &call) {
    frame_complete(call);
    if (double_buffer) {
        drawable->swapBuffers();
    } else {
        glFlush();
    }
}

static void retrace_glXCreateNewContext(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(3).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXMakeContextCurrent(trace::Call &call) {
    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());

    if (new_drawable == drawable && new_context == context) {
        return;
    }

    if (drawable && context) {
        glFlush();
        if (!double_buffer) {
            frame_complete(call);
        }
    }

    bool result = glws::makeCurrent(new_drawable, new_context);

    if (new_drawable && new_context && result) {
        drawable = new_drawable;
        context = new_context;
    } else {
        drawable = NULL;
        context = NULL;
    }
}

const retrace::Entry glretrace::glx_callbacks[] = {
    //{"glXBindChannelToWindowSGIX", &retrace_glXBindChannelToWindowSGIX},
    //{"glXBindSwapBarrierNV", &retrace_glXBindSwapBarrierNV},
    //{"glXBindSwapBarrierSGIX", &retrace_glXBindSwapBarrierSGIX},
    //{"glXBindTexImageEXT", &retrace_glXBindTexImageEXT},
    //{"glXChannelRectSGIX", &retrace_glXChannelRectSGIX},
    //{"glXChannelRectSyncSGIX", &retrace_glXChannelRectSyncSGIX},
    {"glXChooseFBConfig", &retrace::ignore},
    {"glXChooseFBConfigSGIX", &retrace::ignore},
    {"glXChooseVisual", &retrace::ignore},
    //{"glXCopyContext", &retrace_glXCopyContext},
    //{"glXCopyImageSubDataNV", &retrace_glXCopyImageSubDataNV},
    //{"glXCopySubBufferMESA", &retrace_glXCopySubBufferMESA},
    {"glXCreateContextAttribsARB", &retrace_glXCreateContextAttribsARB},
    {"glXCreateContext", &retrace_glXCreateContext},
    //{"glXCreateContextWithConfigSGIX", &retrace_glXCreateContextWithConfigSGIX},
    //{"glXCreateGLXPbufferSGIX", &retrace_glXCreateGLXPbufferSGIX},
    //{"glXCreateGLXPixmap", &retrace_glXCreateGLXPixmap},
    //{"glXCreateGLXPixmapWithConfigSGIX", &retrace_glXCreateGLXPixmapWithConfigSGIX},
    {"glXCreateNewContext", &retrace_glXCreateNewContext},
    //{"glXCreatePbuffer", &retrace_glXCreatePbuffer},
    //{"glXCreatePixmap", &retrace_glXCreatePixmap},
    //{"glXCreateWindow", &retrace_glXCreateWindow},
    //{"glXCushionSGI", &retrace_glXCushionSGI},
    {"glXDestroyContext", &retrace_glXDestroyContext},
    //{"glXDestroyGLXPbufferSGIX", &retrace_glXDestroyGLXPbufferSGIX},
    //{"glXDestroyGLXPixmap", &retrace_glXDestroyGLXPixmap},
    //{"glXDestroyPbuffer", &retrace_glXDestroyPbuffer},
    //{"glXDestroyPixmap", &retrace_glXDestroyPixmap},
    //{"glXDestroyWindow", &retrace_glXDestroyWindow},
    //{"glXFreeContextEXT", &retrace_glXFreeContextEXT},
    {"glXGetAGPOffsetMESA", &retrace::ignore},
    {"glXGetClientString", &retrace::ignore},
    {"glXGetConfig", &retrace::ignore},
    {"glXGetContextIDEXT", &retrace::ignore},
    {"glXGetCurrentContext", &retrace::ignore},
    {"glXGetCurrentDisplayEXT", &retrace::ignore},
    {"glXGetCurrentDisplay", &retrace::ignore},
    {"glXGetCurrentDrawable", &retrace::ignore},
    {"glXGetCurrentReadDrawable", &retrace::ignore},
    {"glXGetCurrentReadDrawableSGI", &retrace::ignore},
    {"glXGetFBConfigAttrib", &retrace::ignore},
    {"glXGetFBConfigAttribSGIX", &retrace::ignore},
    {"glXGetFBConfigFromVisualSGIX", &retrace::ignore},
    {"glXGetFBConfigs", &retrace::ignore},
    {"glXGetMscRateOML", &retrace::ignore},
    {"glXGetProcAddressARB", &retrace::ignore},
    {"glXGetProcAddress", &retrace::ignore},
    {"glXGetSelectedEvent", &retrace::ignore},
    {"glXGetSelectedEventSGIX", &retrace::ignore},
    {"glXGetSyncValuesOML", &retrace::ignore},
    {"glXGetVideoSyncSGI", &retrace::ignore},
    {"glXGetVisualFromFBConfig", &retrace::ignore},
    {"glXGetVisualFromFBConfigSGIX", &retrace::ignore},
    //{"glXImportContextEXT", &retrace_glXImportContextEXT},
    {"glXIsDirect", &retrace::ignore},
    //{"glXJoinSwapGroupNV", &retrace_glXJoinSwapGroupNV},
    //{"glXJoinSwapGroupSGIX", &retrace_glXJoinSwapGroupSGIX},
    {"glXMakeContextCurrent", &retrace_glXMakeContextCurrent},
    //{"glXMakeCurrentReadSGI", &retrace_glXMakeCurrentReadSGI},
    {"glXMakeCurrent", &retrace_glXMakeCurrent},
    {"glXQueryChannelDeltasSGIX", &retrace::ignore},
    {"glXQueryChannelRectSGIX", &retrace::ignore},
    {"glXQueryContextInfoEXT", &retrace::ignore},
    {"glXQueryContext", &retrace::ignore},
    {"glXQueryDrawable", &retrace::ignore},
    {"glXQueryExtension", &retrace::ignore},
    {"glXQueryExtensionsString", &retrace::ignore},
    {"glXQueryFrameCountNV", &retrace::ignore},
    {"glXQueryGLXPbufferSGIX", &retrace::ignore},
    {"glXQueryMaxSwapBarriersSGIX", &retrace::ignore},
    {"glXQueryMaxSwapGroupsNV", &retrace::ignore},
    {"glXQueryServerString", &retrace::ignore},
    {"glXQuerySwapGroupNV", &retrace::ignore},
    {"glXQueryVersion", &retrace::ignore},
    //{"glXReleaseBuffersMESA", &retrace_glXReleaseBuffersMESA},
    //{"glXReleaseTexImageEXT", &retrace_glXReleaseTexImageEXT},
    //{"glXResetFrameCountNV", &retrace_glXResetFrameCountNV},
    //{"glXSelectEvent", &retrace_glXSelectEvent},
    //{"glXSelectEventSGIX", &retrace_glXSelectEventSGIX},
    //{"glXSet3DfxModeMESA", &retrace_glXSet3DfxModeMESA},
    //{"glXSwapBuffersMscOML", &retrace_glXSwapBuffersMscOML},
    {"glXSwapBuffers", &retrace_glXSwapBuffers},
    //{"glXSwapIntervalEXT", &retrace_glXSwapIntervalEXT},
    //{"glXSwapIntervalSGI", &retrace_glXSwapIntervalSGI},
    //{"glXUseXFont", &retrace_glXUseXFont},
    {"glXWaitForMscOML", &retrace::ignore},
    {"glXWaitForSbcOML", &retrace::ignore},
    {"glXWaitGL", &retrace::ignore},
    {"glXWaitVideoSyncSGI", &retrace::ignore},
    {"glXWaitX", &retrace::ignore},
    {NULL, NULL},
};

<commit_msg>Ignore glXSwapInterval* when retracing.<commit_after>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include "glproc.hpp"
#include "retrace.hpp"
#include "glretrace.hpp"

using namespace glretrace;

typedef std::map<unsigned long, glws::Drawable *> DrawableMap;
typedef std::map<unsigned long long, glws::Context *> ContextMap;
static DrawableMap drawable_map;
static ContextMap context_map;

static glws::Drawable *
getDrawable(unsigned long drawable_id) {
    if (drawable_id == 0) {
        return NULL;
    }

    DrawableMap::const_iterator it;
    it = drawable_map.find(drawable_id);
    if (it == drawable_map.end()) {
        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
    }

    return it->second;
}

static glws::Context *
getContext(unsigned long long context_ptr) {
    if (context_ptr == 0) {
        return NULL;
    }

    ContextMap::const_iterator it;
    it = context_map.find(context_ptr);
    if (it == context_map.end()) {
        return (context_map[context_ptr] = glws::createContext(visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile));
    }

    return it->second;
}

static void retrace_glXCreateContext(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXCreateContextAttribsARB(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXMakeCurrent(trace::Call &call) {
    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
    glws::Context *new_context = getContext(call.arg(2).toUIntPtr());

    if (new_drawable == drawable && new_context == context) {
        return;
    }

    if (drawable && context) {
        glFlush();
        if (!double_buffer) {
            frame_complete(call);
        }
    }

    bool result = glws::makeCurrent(new_drawable, new_context);

    if (new_drawable && new_context && result) {
        drawable = new_drawable;
        context = new_context;
    } else {
        drawable = NULL;
        context = NULL;
    }
}

static void retrace_glXDestroyContext(trace::Call &call) {
    glws::Context *context = getContext(call.arg(1).toUIntPtr());

    if (!context) {
        return;
    }

    delete context;
}

static void retrace_glXSwapBuffers(trace::Call &call) {
    frame_complete(call);
    if (double_buffer) {
        drawable->swapBuffers();
    } else {
        glFlush();
    }
}

static void retrace_glXCreateNewContext(trace::Call &call) {
    unsigned long long orig_context = call.ret->toUIntPtr();
    glws::Context *share_context = getContext(call.arg(3).toUIntPtr());

    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
    context_map[orig_context] = context;
}

static void retrace_glXMakeContextCurrent(trace::Call &call) {
    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());

    if (new_drawable == drawable && new_context == context) {
        return;
    }

    if (drawable && context) {
        glFlush();
        if (!double_buffer) {
            frame_complete(call);
        }
    }

    bool result = glws::makeCurrent(new_drawable, new_context);

    if (new_drawable && new_context && result) {
        drawable = new_drawable;
        context = new_context;
    } else {
        drawable = NULL;
        context = NULL;
    }
}

const retrace::Entry glretrace::glx_callbacks[] = {
    //{"glXBindChannelToWindowSGIX", &retrace_glXBindChannelToWindowSGIX},
    //{"glXBindSwapBarrierNV", &retrace_glXBindSwapBarrierNV},
    //{"glXBindSwapBarrierSGIX", &retrace_glXBindSwapBarrierSGIX},
    //{"glXBindTexImageEXT", &retrace_glXBindTexImageEXT},
    //{"glXChannelRectSGIX", &retrace_glXChannelRectSGIX},
    //{"glXChannelRectSyncSGIX", &retrace_glXChannelRectSyncSGIX},
    {"glXChooseFBConfig", &retrace::ignore},
    {"glXChooseFBConfigSGIX", &retrace::ignore},
    {"glXChooseVisual", &retrace::ignore},
    //{"glXCopyContext", &retrace_glXCopyContext},
    //{"glXCopyImageSubDataNV", &retrace_glXCopyImageSubDataNV},
    //{"glXCopySubBufferMESA", &retrace_glXCopySubBufferMESA},
    {"glXCreateContextAttribsARB", &retrace_glXCreateContextAttribsARB},
    {"glXCreateContext", &retrace_glXCreateContext},
    //{"glXCreateContextWithConfigSGIX", &retrace_glXCreateContextWithConfigSGIX},
    //{"glXCreateGLXPbufferSGIX", &retrace_glXCreateGLXPbufferSGIX},
    //{"glXCreateGLXPixmap", &retrace_glXCreateGLXPixmap},
    //{"glXCreateGLXPixmapWithConfigSGIX", &retrace_glXCreateGLXPixmapWithConfigSGIX},
    {"glXCreateNewContext", &retrace_glXCreateNewContext},
    //{"glXCreatePbuffer", &retrace_glXCreatePbuffer},
    //{"glXCreatePixmap", &retrace_glXCreatePixmap},
    //{"glXCreateWindow", &retrace_glXCreateWindow},
    //{"glXCushionSGI", &retrace_glXCushionSGI},
    {"glXDestroyContext", &retrace_glXDestroyContext},
    //{"glXDestroyGLXPbufferSGIX", &retrace_glXDestroyGLXPbufferSGIX},
    //{"glXDestroyGLXPixmap", &retrace_glXDestroyGLXPixmap},
    //{"glXDestroyPbuffer", &retrace_glXDestroyPbuffer},
    //{"glXDestroyPixmap", &retrace_glXDestroyPixmap},
    //{"glXDestroyWindow", &retrace_glXDestroyWindow},
    //{"glXFreeContextEXT", &retrace_glXFreeContextEXT},
    {"glXGetAGPOffsetMESA", &retrace::ignore},
    {"glXGetClientString", &retrace::ignore},
    {"glXGetConfig", &retrace::ignore},
    {"glXGetContextIDEXT", &retrace::ignore},
    {"glXGetCurrentContext", &retrace::ignore},
    {"glXGetCurrentDisplayEXT", &retrace::ignore},
    {"glXGetCurrentDisplay", &retrace::ignore},
    {"glXGetCurrentDrawable", &retrace::ignore},
    {"glXGetCurrentReadDrawable", &retrace::ignore},
    {"glXGetCurrentReadDrawableSGI", &retrace::ignore},
    {"glXGetFBConfigAttrib", &retrace::ignore},
    {"glXGetFBConfigAttribSGIX", &retrace::ignore},
    {"glXGetFBConfigFromVisualSGIX", &retrace::ignore},
    {"glXGetFBConfigs", &retrace::ignore},
    {"glXGetMscRateOML", &retrace::ignore},
    {"glXGetProcAddressARB", &retrace::ignore},
    {"glXGetProcAddress", &retrace::ignore},
    {"glXGetSelectedEvent", &retrace::ignore},
    {"glXGetSelectedEventSGIX", &retrace::ignore},
    {"glXGetSyncValuesOML", &retrace::ignore},
    {"glXGetVideoSyncSGI", &retrace::ignore},
    {"glXGetVisualFromFBConfig", &retrace::ignore},
    {"glXGetVisualFromFBConfigSGIX", &retrace::ignore},
    //{"glXImportContextEXT", &retrace_glXImportContextEXT},
    {"glXIsDirect", &retrace::ignore},
    //{"glXJoinSwapGroupNV", &retrace_glXJoinSwapGroupNV},
    //{"glXJoinSwapGroupSGIX", &retrace_glXJoinSwapGroupSGIX},
    {"glXMakeContextCurrent", &retrace_glXMakeContextCurrent},
    //{"glXMakeCurrentReadSGI", &retrace_glXMakeCurrentReadSGI},
    {"glXMakeCurrent", &retrace_glXMakeCurrent},
    {"glXQueryChannelDeltasSGIX", &retrace::ignore},
    {"glXQueryChannelRectSGIX", &retrace::ignore},
    {"glXQueryContextInfoEXT", &retrace::ignore},
    {"glXQueryContext", &retrace::ignore},
    {"glXQueryDrawable", &retrace::ignore},
    {"glXQueryExtension", &retrace::ignore},
    {"glXQueryExtensionsString", &retrace::ignore},
    {"glXQueryFrameCountNV", &retrace::ignore},
    {"glXQueryGLXPbufferSGIX", &retrace::ignore},
    {"glXQueryMaxSwapBarriersSGIX", &retrace::ignore},
    {"glXQueryMaxSwapGroupsNV", &retrace::ignore},
    {"glXQueryServerString", &retrace::ignore},
    {"glXQuerySwapGroupNV", &retrace::ignore},
    {"glXQueryVersion", &retrace::ignore},
    //{"glXReleaseBuffersMESA", &retrace_glXReleaseBuffersMESA},
    //{"glXReleaseTexImageEXT", &retrace_glXReleaseTexImageEXT},
    //{"glXResetFrameCountNV", &retrace_glXResetFrameCountNV},
    //{"glXSelectEvent", &retrace_glXSelectEvent},
    //{"glXSelectEventSGIX", &retrace_glXSelectEventSGIX},
    //{"glXSet3DfxModeMESA", &retrace_glXSet3DfxModeMESA},
    //{"glXSwapBuffersMscOML", &retrace_glXSwapBuffersMscOML},
    {"glXSwapBuffers", &retrace_glXSwapBuffers},
    {"glXSwapIntervalEXT", &retrace::ignore},
    {"glXSwapIntervalSGI", &retrace::ignore},
    //{"glXUseXFont", &retrace_glXUseXFont},
    {"glXWaitForMscOML", &retrace::ignore},
    {"glXWaitForSbcOML", &retrace::ignore},
    {"glXWaitGL", &retrace::ignore},
    {"glXWaitVideoSyncSGI", &retrace::ignore},
    {"glXWaitX", &retrace::ignore},
    {NULL, NULL},
};

<|endoftext|>


<commit_before>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * This GM exercises stroking of paths with large stroke lengths, which is
 * referred to as "overstroke" for brevity. In Skia as of 8/2016 we offset
 * each part of the curve the request amount even if it makes the offsets
 * overlap and create holes. There is not a really great algorithm for this
 * and several other 2D graphics engines have the same bug.
 *
 * See crbug.com/589769 skbug.com/5405 skbug.com/5406
 */

#include "gm.h"
#include "SkPaint.h"
#include "SkPath.h"

//////// path and paint builders

SkPaint make_overstroke_paint() {
    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(500);

    return p;
}

SkPath quad_path() {
    SkPath path;
    path.moveTo(0, 0);
    path.lineTo(100, 0);
    path.quadTo(50, -40,
                0, 0);

    return path;
}

SkPath cubic_path() {
    SkPath path;
    path.moveTo(0, 0);
    path.cubicTo(25, 75,
                 75, -50,
                 100, 0);

    return path;
}

SkPath oval_path() {
    SkRect oval = SkRect::MakeXYWH(0, -25, 100, 50);

    SkPath path;
    path.arcTo(oval, 0, 359, true);
    path.close();

    return path;
}

///////// quads

void draw_small_quad(SkCanvas *canvas) {
    // scaled so it's visible
    canvas->scale(8, 8);

    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(3);

    SkPath path = quad_path();

    canvas->drawPath(path, p);
}

void draw_large_quad(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = quad_path();

    canvas->drawPath(path, p);
}

void draw_quad_fillpath(SkCanvas *canvas) {
    SkPath path = quad_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp;
    fillp.setAntiAlias(true);
    fillp.setStyle(SkPaint::kStroke_Style);
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_quad(SkCanvas *canvas) {
    canvas->translate(200, 0);
    draw_large_quad(canvas);
    draw_quad_fillpath(canvas);
}

////////// cubics

void draw_small_cubic(SkCanvas *canvas) {
    // scaled so it's visible
    canvas->scale(8, 8);

    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(3);

    SkPath path = cubic_path();

    canvas->drawPath(path, p);
}

void draw_large_cubic(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = cubic_path();

    canvas->drawPath(path, p);
}

void draw_cubic_fillpath(SkCanvas *canvas) {
    SkPath path = cubic_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp;
    fillp.setAntiAlias(true);
    fillp.setStyle(SkPaint::kStroke_Style);
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_cubic(SkCanvas *canvas) {
    canvas->translate(400, 0);
    draw_large_cubic(canvas);
    draw_cubic_fillpath(canvas);
}

////////// ovals

void draw_small_oval(SkCanvas *canvas) {
    // scaled so it's visible
    canvas->scale(8, 8);

    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(3);

    SkPath path = oval_path();

    canvas->drawPath(path, p);
}

void draw_large_oval(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = oval_path();

    canvas->drawPath(path, p);
}

void draw_oval_fillpath(SkCanvas *canvas) {
    SkPath path = oval_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp;
    fillp.setAntiAlias(true);
    fillp.setStyle(SkPaint::kStroke_Style);
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_oval(SkCanvas *canvas) {
    canvas->translate(400, 0);
    draw_large_oval(canvas);
    draw_oval_fillpath(canvas);
}

////////// gm

void (*examples[])(SkCanvas *canvas) = {
    draw_small_quad,    draw_stroked_quad, draw_small_cubic,
    draw_stroked_cubic, draw_small_oval,   draw_stroked_oval,
};

DEF_SIMPLE_GM(OverStroke, canvas, 500, 500) {
    const size_t length = sizeof(examples) / sizeof(examples[0]);
    const size_t width = 2;

    for (size_t i = 0; i < length; i++) {
        int x = (int)(i % width);
        int y = (int)(i / width);

        canvas->save();
        canvas->translate(200.0f * x, 150.0f * y);
        canvas->scale(0.25f, 0.25f);
        canvas->translate(100.0f, 400.0f);

        examples[i](canvas);

        canvas->restore();
    }
}
<commit_msg>Rework Overstroke GM to show differences between expected and actual<commit_after>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * This GM exercises stroking of paths with large stroke lengths, which is
 * referred to as "overstroke" for brevity. In Skia as of 8/2016 we offset
 * each part of the curve the request amount even if it makes the offsets
 * overlap and create holes. There is not a really great algorithm for this
 * and several other 2D graphics engines have the same bug.
 *
 * If we run this using Nvidia Path Renderer with:
 * `path/to/dm --match OverStroke -w gm_out --gpu --config nvpr16`
 * then we get correct results, so that is a possible direction of attack -
 * use the GPU and a completely different algorithm to get correctness in
 * Skia.
 *
 * See crbug.com/589769 skbug.com/5405 skbug.com/5406
 */

#include "gm.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPathMeasure.h"

const SkScalar OVERSTROKE_WIDTH = 500.0f;
const SkScalar NORMALSTROKE_WIDTH = 3.0f;

//////// path and paint builders

SkPaint make_normal_paint() {
    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(NORMALSTROKE_WIDTH);
    p.setColor(SK_ColorBLUE);

    return p;
}

SkPaint make_overstroke_paint() {
    SkPaint p;
    p.setAntiAlias(true);
    p.setStyle(SkPaint::kStroke_Style);
    p.setStrokeWidth(OVERSTROKE_WIDTH);

    return p;
}

SkPath quad_path() {
    SkPath path;
    path.moveTo(0, 0);
    path.lineTo(100, 0);
    path.quadTo(50, -40,
                0, 0);
    path.close();

    return path;
}

SkPath cubic_path() {
    SkPath path;
    path.moveTo(0, 0);
    path.cubicTo(25, 75,
                 75, -50,
                 100, 0);

    return path;
}

SkPath oval_path() {
    SkRect oval = SkRect::MakeXYWH(0, -25, 100, 50);

    SkPath path;
    path.arcTo(oval, 0, 359, true);
    path.close();

    return path;
}

SkPath ribs_path(SkPath path, SkScalar radius) {
    SkPath ribs;

    const SkScalar spacing = 5.0f;
    float accum = 0.0f;

    SkPathMeasure meas(path, false);
    SkScalar length = meas.getLength();
    SkPoint pos;
    SkVector tan;
    while (accum < length) {
        if (meas.getPosTan(accum, &pos, &tan)) {
            tan.scale(radius);
            tan.rotateCCW();

            ribs.moveTo(pos.x() + tan.x(), pos.y() + tan.y());
            ribs.lineTo(pos.x() - tan.x(), pos.y() - tan.y());
        }
        accum += spacing;
    }

    return ribs;
}

void draw_ribs(SkCanvas *canvas, SkPath path) {
    SkPath ribs = ribs_path(path, OVERSTROKE_WIDTH/2.0f);
    SkPaint p = make_normal_paint();
    p.setStrokeWidth(1);
    p.setColor(SK_ColorBLUE);
    p.setColor(SK_ColorGREEN);

    canvas->drawPath(ribs, p);
}

///////// quads

void draw_small_quad(SkCanvas *canvas) {
    // scaled so it's visible
    // canvas->scale(8, 8);

    SkPaint p = make_normal_paint();
    SkPath path = quad_path();

    draw_ribs(canvas, path);
    canvas->drawPath(path, p);
}

void draw_large_quad(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = quad_path();

    canvas->drawPath(path, p);
    draw_ribs(canvas, path);
}

void draw_quad_fillpath(SkCanvas *canvas) {
    SkPath path = quad_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp = make_normal_paint();
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_quad(SkCanvas *canvas) {
    canvas->translate(400, 0);
    draw_large_quad(canvas);
    draw_quad_fillpath(canvas);
}

////////// cubics

void draw_small_cubic(SkCanvas *canvas) {
    SkPaint p = make_normal_paint();
    SkPath path = cubic_path();

    draw_ribs(canvas, path);
    canvas->drawPath(path, p);
}

void draw_large_cubic(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = cubic_path();

    canvas->drawPath(path, p);
    draw_ribs(canvas, path);
}

void draw_cubic_fillpath(SkCanvas *canvas) {
    SkPath path = cubic_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp = make_normal_paint();
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_cubic(SkCanvas *canvas) {
    canvas->translate(400, 0);
    draw_large_cubic(canvas);
    draw_cubic_fillpath(canvas);
}

////////// ovals

void draw_small_oval(SkCanvas *canvas) {
    SkPaint p = make_normal_paint();

    SkPath path = oval_path();

    draw_ribs(canvas, path);
    canvas->drawPath(path, p);
}

void draw_large_oval(SkCanvas *canvas) {
    SkPaint p = make_overstroke_paint();
    SkPath path = oval_path();

    canvas->drawPath(path, p);
    draw_ribs(canvas, path);
}

void draw_oval_fillpath(SkCanvas *canvas) {
    SkPath path = oval_path();
    SkPaint p = make_overstroke_paint();

    SkPaint fillp = make_normal_paint();
    fillp.setColor(SK_ColorMAGENTA);

    SkPath fillpath;
    p.getFillPath(path, &fillpath);

    canvas->drawPath(fillpath, fillp);
}

void draw_stroked_oval(SkCanvas *canvas) {
    canvas->translate(400, 0);
    draw_large_oval(canvas);
    draw_oval_fillpath(canvas);
}

////////// gm

void (*examples[])(SkCanvas *canvas) = {
    draw_small_quad,    draw_stroked_quad, draw_small_cubic,
    draw_stroked_cubic, draw_small_oval,   draw_stroked_oval,
};

DEF_SIMPLE_GM(OverStroke, canvas, 500, 500) {
    const size_t length = sizeof(examples) / sizeof(examples[0]);
    const size_t width = 2;

    for (size_t i = 0; i < length; i++) {
        int x = (int)(i % width);
        int y = (int)(i / width);

        canvas->save();
        canvas->translate(150.0f * x, 150.0f * y);
        canvas->scale(0.2f, 0.2f);
        canvas->translate(300.0f, 400.0f);

        examples[i](canvas);

        canvas->restore();
    }
}
<|endoftext|>


<commit_before>// (c) Ivan Gagis
// e-mail: igagis@gmail.com

#include <ting/debug.hpp>
#include <ting/Thread.hpp>

#include "Connection.hpp"
#include "ConnectionsThread.hpp"

using namespace cliser;

void Connection::Send_ts(ting::Array<ting::u8> data){
	ting::Mutex::Guard mutexGuard(this->parentThreadMutex);//make sure that this->clientThread won't be zeroed out by other thread
	if(!this->parentThread){
		//client disconnected, do nothing
//		TRACE(<< "Connection::" << __func__ << "(): client disconnected" << std::endl)
		return;
	}
	ASSERT(this->parentThread)

	ting::Ref<Connection> c(this);
	this->parentThread->PushMessage(
			ting::Ptr<ting::Message>(
					new ConnectionsThread::SendDataMessage(this->parentThread, c, data)
				)
		);
}

void Connection::SendCopy_ts(const ting::Buffer<ting::u8>& data){
	ting::Array<ting::u8> buf(data);

	this->Send_ts(buf);
}

void Connection::Disconnect_ts(){
	ting::Mutex::Guard mutexGuard(this->parentThreadMutex);
	if(!this->parentThread){
		//client disconnected, do nothing
		return;
	}
	ASSERT(this->parentThread)
	ting::Ref<Connection> c(this);
	this->parentThread->PushMessage(
			ting::Ptr<ting::Message>(
					new ConnectionsThread::RemoveConnectionMessage(this->parentThread, c)
				)
		);

	this->parentThread = 0;
}

ting::Array<ting::u8> Connection::GetReceivedData_ts(){
	ting::Mutex::Guard mutexGuard(this->receivedDataMutex);

	ting::Array<ting::u8> ret;

	//Send the message to parent thread only if
	//there was received data stored, which means
	//that socket is not listened for READ condition.
	if(this->receivedData && this->parentThread){
		ting::Ref<Connection> c(this);
		ASSERT(c)

		ret = this->receivedData;

		//send message to parentHandler thread
		ASS(this->parentThread)->PushMessage(
				ting::Ptr<ting::Message>(
						new ConnectionsThread::ResumeListeningForReadMessage(this->parentThread, c)
					)
			);
	}

	return ret;
}

<commit_msg>refactoring<commit_after>// (c) Ivan Gagis
// e-mail: igagis@gmail.com

#include <ting/debug.hpp>
#include <ting/Thread.hpp>

#include "Connection.hpp"
#include "ConnectionsThread.hpp"

using namespace cliser;

void Connection::Send_ts(ting::Array<ting::u8> data){
	ting::Mutex::Guard mutexGuard(this->parentThreadMutex);//make sure that this->clientThread won't be zeroed out by other thread
	if(!this->parentThread){
		//client disconnected, do nothing
//		TRACE(<< "Connection::" << __func__ << "(): client disconnected" << std::endl)
		return;
	}
	ASSERT(this->parentThread)

	ting::Ref<Connection> c(this);
	this->parentThread->PushMessage(
			ting::Ptr<ting::Message>(
					new ConnectionsThread::SendDataMessage(this->parentThread, c, data)
				)
		);
}

void Connection::SendCopy_ts(const ting::Buffer<ting::u8>& data){
	ting::Array<ting::u8> buf(data);

	this->Send_ts(buf);
}

void Connection::Disconnect_ts(){
	ting::Mutex::Guard mutexGuard(this->parentThreadMutex);
	if(!this->parentThread){
		//client disconnected, do nothing
		return;
	}
	ASSERT(this->parentThread)
	ting::Ref<Connection> c(this);
	this->parentThread->PushMessage(
			ting::Ptr<ting::Message>(
					new ConnectionsThread::RemoveConnectionMessage(this->parentThread, c)
				)
		);

	this->parentThread = 0;
}

ting::Array<ting::u8> Connection::GetReceivedData_ts(){
	ting::Mutex::Guard mutexGuard(this->receivedDataMutex);

	ting::Array<ting::u8> ret = this->receivedData;

	//Send the message to parent thread only if
	//there was received data stored, which means
	//that socket is not listened for READ condition.
	if(ret){
		ting::Mutex::Guard parentThreadMutextGuard(this->parentThreadMutex);
		if(this->parentThread){
			ting::Ref<Connection> c(this);
			ASSERT(c)

			//send message to parentHandler thread
			ASS(this->parentThread)->PushMessage(
					ting::Ptr<ting::Message>(
							new ConnectionsThread::ResumeListeningForReadMessage(this->parentThread, c)
						)
				);
		}
	}

	return ret;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: finteraction.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 15:48:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef DBAUI_FILEPICKER_INTERACTION_HXX
#define DBAUI_FILEPICKER_INTERACTION_HXX

#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COM_SUN_STAR_TASK_XINTERACTIONHANDLER_HPP_
#include <com/sun/star/task/XInteractionHandler.hpp>
#endif

//........................................................................
namespace dbaui
{
//........................................................................

    //====================================================================
    //= OFilePickerInteractionHandler
    //====================================================================
    typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::task::XInteractionHandler
                                    >   OFilePickerInteractionHandler_Base;

    /** a InteractionHandler implementation which extends another handler with some customizability
    */
    class OFilePickerInteractionHandler : public OFilePickerInteractionHandler_Base
    {
    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
                    m_xMaster;      // our master handler
        sal_Bool    m_bDoesNotExist;

    public:
        OFilePickerInteractionHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& _rxMaster );

        inline sal_Bool isDoesNotExist( ) const { return m_bDoesNotExist; }

    protected:
        // XInteractionHandler
        virtual void SAL_CALL handle( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& _rxRequest ) throw (::com::sun::star::uno::RuntimeException);

        virtual ~OFilePickerInteractionHandler();
    };

//........................................................................
}   // namespace dbaui
//........................................................................

#endif // DBAUI_FILEPICKER_INTERACTION_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.204); FILE MERGED 2005/09/05 17:33:53 rt 1.3.204.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: finteraction.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:04:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef DBAUI_FILEPICKER_INTERACTION_HXX
#define DBAUI_FILEPICKER_INTERACTION_HXX

#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COM_SUN_STAR_TASK_XINTERACTIONHANDLER_HPP_
#include <com/sun/star/task/XInteractionHandler.hpp>
#endif

//........................................................................
namespace dbaui
{
//........................................................................

    //====================================================================
    //= OFilePickerInteractionHandler
    //====================================================================
    typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::task::XInteractionHandler
                                    >   OFilePickerInteractionHandler_Base;

    /** a InteractionHandler implementation which extends another handler with some customizability
    */
    class OFilePickerInteractionHandler : public OFilePickerInteractionHandler_Base
    {
    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >
                    m_xMaster;      // our master handler
        sal_Bool    m_bDoesNotExist;

    public:
        OFilePickerInteractionHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& _rxMaster );

        inline sal_Bool isDoesNotExist( ) const { return m_bDoesNotExist; }

    protected:
        // XInteractionHandler
        virtual void SAL_CALL handle( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& _rxRequest ) throw (::com::sun::star::uno::RuntimeException);

        virtual ~OFilePickerInteractionHandler();
    };

//........................................................................
}   // namespace dbaui
//........................................................................

#endif // DBAUI_FILEPICKER_INTERACTION_HXX

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ScrollHelper.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2004-01-06 16:46:28 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the License); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an AS IS basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef DBAUI_SCROLLHELPER_HXX
#define DBAUI_SCROLLHELPER_HXX

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _SV_TIMER_HXX
#include <vcl/timer.hxx>
#endif

namespace dbaui
{
    class OScrollHelper
    {
        Link    m_aUpScroll;
        Link    m_aDownScroll;
    public:
        /** default contructor
        */
        OScrollHelper();

        ~OScrollHelper();

        /** set the memthod which should be called when scrolling up
            @param  _rUpScroll
                the method to set
        */
        inline void setUpScrollMethod( const Link& _rUpScroll )
        {
            m_aUpScroll = _rUpScroll;
        }

        /** set the memthod which should be called when scrolling down
            @param  _rDownScroll
                the method to set
        */
        inline void setDownScrollMethod( const Link& _rDownScroll )
        {
            m_aDownScroll = _rDownScroll;
        }

        /** check if a scroll method has to be called
            @param  _rPoint
                the current selection point
            @param  _rOutputSize
                the output size of the window
        */
        void scroll(const Point& _rPoint, const Size& _rOutputSize);
    };
}
#endif // DBAUI_SCROLLHELPER_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.284); FILE MERGED 2005/09/05 17:34:26 rt 1.3.284.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ScrollHelper.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:34:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef DBAUI_SCROLLHELPER_HXX
#define DBAUI_SCROLLHELPER_HXX

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _SV_TIMER_HXX
#include <vcl/timer.hxx>
#endif

namespace dbaui
{
    class OScrollHelper
    {
        Link    m_aUpScroll;
        Link    m_aDownScroll;
    public:
        /** default contructor
        */
        OScrollHelper();

        ~OScrollHelper();

        /** set the memthod which should be called when scrolling up
            @param  _rUpScroll
                the method to set
        */
        inline void setUpScrollMethod( const Link& _rUpScroll )
        {
            m_aUpScroll = _rUpScroll;
        }

        /** set the memthod which should be called when scrolling down
            @param  _rDownScroll
                the method to set
        */
        inline void setDownScrollMethod( const Link& _rDownScroll )
        {
            m_aDownScroll = _rDownScroll;
        }

        /** check if a scroll method has to be called
            @param  _rPoint
                the current selection point
            @param  _rOutputSize
                the output size of the window
        */
        void scroll(const Point& _rPoint, const Size& _rOutputSize);
    };
}
#endif // DBAUI_SCROLLHELPER_HXX

<|endoftext|>