Global Metrics

path: .metrics.cyclomatic.sum
old: 121.0
new: 25.0

path: .metrics.cyclomatic.average
old: 2.1607142857142856
new: 1.6666666666666667

path: .metrics.mi.mi_sei
old: -66.52767086372864
new: -0.25675347532985526

path: .metrics.mi.mi_original
old: -16.582158762728383
new: 34.29280974268012

path: .metrics.mi.mi_visual_studio
old: 0.0
new: 20.054274703321703

path: .metrics.loc.ploc
old: 577.0
new: 151.0

path: .metrics.loc.blank
old: 111.0
new: 40.0

path: .metrics.loc.cloc
old: 57.0
new: 21.0

path: .metrics.loc.sloc
old: 745.0
new: 212.0

path: .metrics.loc.lloc
old: 184.0
new: 68.0

path: .metrics.cognitive.sum
old: 86.0
new: 12.0

path: .metrics.cognitive.average
old: 1.6862745098039216
new: 0.8571428571428571

path: .metrics.nargs.sum
old: 112.0
new: 3.0

path: .metrics.nargs.average
old: 2.196078431372549
new: 0.21428571428571427

path: .metrics.nexits.average
old: 1.3725490196078431
new: 0.7142857142857143

path: .metrics.nexits.sum
old: 70.0
new: 10.0

path: .metrics.halstead.estimated_program_length
old: 1929.7836052918128
new: 841.5415307421127

path: .metrics.halstead.N2
old: 1270.0
new: 286.0

path: .metrics.halstead.length
old: 3097.0
new: 694.0

path: .metrics.halstead.volume
old: 24793.419228853443
new: 4896.366010237825

path: .metrics.halstead.bugs
old: 5.15822811283093
new: 1.0561459852936046

path: .metrics.halstead.N1
old: 1827.0
new: 408.0

path: .metrics.halstead.vocabulary
old: 257.0
new: 133.0

path: .metrics.halstead.time
old: 106944.92816327373
new: 9908.21235090579

path: .metrics.halstead.n1
old: 28.0
new: 27.0

path: .metrics.halstead.difficulty
old: 77.64192139737992
new: 36.424528301886795

path: .metrics.halstead.level
old: 0.012879640044994376
new: 0.027454027454027453

path: .metrics.halstead.n2
old: 229.0
new: 106.0

path: .metrics.halstead.purity_ratio
old: 0.6231138538236399
new: 1.2125958656226408

path: .metrics.halstead.effort
old: 1925008.7069389268
new: 178347.8223163042

path: .metrics.nom.closures
old: 0.0
new: 2.0

path: .metrics.nom.total
old: 51.0
new: 14.0

path: .metrics.nom.functions
old: 51.0
new: 12.0

Spaces Data

Minimal test - lines (19, 212)

path: .spaces[0].metrics.nexits.average
old: 1.0
new: 0.7142857142857143

path: .spaces[0].metrics.nexits.sum
old: 1.0
new: 10.0

path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.7142857142857142

path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 24.0

path: .spaces[0].metrics.loc.ploc
old: 5.0
new: 141.0

path: .spaces[0].metrics.loc.sloc
old: 6.0
new: 194.0

path: .spaces[0].metrics.loc.blank
old: 0.0
new: 38.0

path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 15.0

path: .spaces[0].metrics.loc.lloc
old: 1.0
new: 68.0

path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 12.0

path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 0.8571428571428571

path: .spaces[0].metrics.halstead.n1
old: 9.0
new: 27.0

path: .spaces[0].metrics.halstead.estimated_program_length
old: 57.05865002596162
new: 768.573508250565

path: .spaces[0].metrics.halstead.difficulty
old: 6.0
new: 38.41237113402062

path: .spaces[0].metrics.halstead.effort
old: 650.5083002250007
new: 182447.85684596415

path: .spaces[0].metrics.halstead.time
old: 36.13935001250004
new: 10135.992046998008

path: .spaces[0].metrics.halstead.N2
old: 12.0
new: 276.0

path: .spaces[0].metrics.halstead.N1
old: 14.0
new: 407.0

path: .spaces[0].metrics.halstead.length
old: 26.0
new: 683.0

path: .spaces[0].metrics.halstead.volume
old: 108.41805003750012
new: 4749.716079994236

path: .spaces[0].metrics.halstead.level
old: 0.16666666666666666
new: 0.026033279656468063

path: .spaces[0].metrics.halstead.purity_ratio
old: 2.194563462536985
new: 1.1252906416552928

path: .spaces[0].metrics.halstead.bugs
old: 0.02502537766060993
new: 1.0722710714706876

path: .spaces[0].metrics.halstead.n2
old: 9.0
new: 97.0

path: .spaces[0].metrics.halstead.vocabulary
old: 18.0
new: 124.0

path: .spaces[0].metrics.nargs.average
old: 1.0
new: 0.21428571428571427

path: .spaces[0].metrics.nargs.sum
old: 1.0
new: 3.0

path: .spaces[0].metrics.nom.functions
old: 1.0
new: 12.0

path: .spaces[0].metrics.nom.closures
old: 0.0
new: 2.0

path: .spaces[0].metrics.nom.total
old: 1.0
new: 14.0

path: .spaces[0].metrics.mi.mi_visual_studio
old: 68.64112557824586
new: 21.121829933102344

path: .spaces[0].metrics.mi.mi_original
old: 117.37632473880043
new: 36.118329185605006

path: .spaces[0].metrics.mi.mi_sei
old: 123.29556534659632
new: -0.2706894464990661

Code

namespace mozilla {
namespace widget {

static StaticRefPtr sWinCompositorWindowThread;

WinCompositorWindowThread::WinCompositorWindowThread(base::Thread* aThread)
    : mThread(aThread) {}

WinCompositorWindowThread::~WinCompositorWindowThread() { delete mThread; }

/* static */
WinCompositorWindowThread* WinCompositorWindowThread::Get() {
  return sWinCompositorWindowThread;
}

/* static */
void WinCompositorWindowThread::Start() {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!sWinCompositorWindowThread);

  base::Thread* thread = new base::Thread("WinCompositor");

  base::Thread::Options options;
  // HWND requests ui thread.
  options.message_loop_type = MessageLoop::TYPE_UI;

  if (!thread->StartWithOptions(options)) {
    delete thread;
    return;
  }

  sWinCompositorWindowThread = new WinCompositorWindowThread(thread);
}

/* static */
void WinCompositorWindowThread::ShutDown() {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(sWinCompositorWindowThread);

  layers::SynchronousTask task("WinCompositorWindowThread");
  RefPtr runnable = WrapRunnable(
      RefPtr(sWinCompositorWindowThread.get()),
      &WinCompositorWindowThread::ShutDownTask, &task);
  sWinCompositorWindowThread->Loop()->PostTask(runnable.forget());
  task.Wait();

  sWinCompositorWindowThread = nullptr;
}

void WinCompositorWindowThread::ShutDownTask(layers::SynchronousTask* aTask) {
  layers::AutoCompleteTask complete(aTask);
  MOZ_ASSERT(IsInCompositorWindowThread());
}

/* static */
MessageLoop* WinCompositorWindowThread::Loop() {
  return sWinCompositorWindowThread
             ? sWinCompositorWindowThread->mThread->message_loop()
             : nullptr;
}

/* static */
bool WinCompositorWindowThread::IsInCompositorWindowThread() {
  return sWinCompositorWindowThread &&
         sWinCompositorWindowThread->mThread->thread_id() ==
             PlatformThread::CurrentId();
}

const wchar_t kClassNameCompositorInitalParent[] =
    L"MozillaCompositorInitialParentClass";
const wchar_t kClassNameCompositor[] = L"MozillaCompositorWindowClass";

ATOM g_compositor_inital_parent_window_class;
ATOM g_compositor_window_class;

// This runs on the window owner thread.
void InitializeInitialParentWindowClass() {
  if (g_compositor_inital_parent_window_class) {
    return;
  }

  WNDCLASSW wc;
  wc.style = 0;
  wc.lpfnWndProc = ::DefWindowProcW;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = GetModuleHandle(nullptr);
  wc.hIcon = nullptr;
  wc.hCursor = nullptr;
  wc.hbrBackground = nullptr;
  wc.lpszMenuName = nullptr;
  wc.lpszClassName = kClassNameCompositorInitalParent;
  g_compositor_inital_parent_window_class = ::RegisterClassW(&wc);
}

// This runs on the window owner thread.
void InitializeWindowClass() {
  if (g_compositor_window_class) {
    return;
  }

  WNDCLASSW wc;
  wc.style = CS_OWNDC;
  wc.lpfnWndProc = ::DefWindowProcW;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = GetModuleHandle(nullptr);
  wc.hIcon = nullptr;
  wc.hCursor = nullptr;
  wc.hbrBackground = nullptr;
  wc.lpszMenuName = nullptr;
  wc.lpszClassName = kClassNameCompositor;
  g_compositor_window_class = ::RegisterClassW(&wc);
}

/* static */
WinCompositorWnds WinCompositorWindowThread::CreateCompositorWindow() {
  MOZ_ASSERT(Loop());

  if (!Loop()) {
    return WinCompositorWnds(nullptr, nullptr);
  }

  layers::SynchronousTask task("Create compositor window");

  HWND initialParentWnd = nullptr;
  HWND compositorWnd = nullptr;

  RefPtr runnable = NS_NewRunnableFunction(
      "WinCompositorWindowThread::CreateCompositorWindow::Runnable", [&]() {
        layers::AutoCompleteTask complete(&task);

        InitializeInitialParentWindowClass();
        InitializeWindowClass();

        // Create initial parent window.
        // We could not directly create a compositor window with a main window
        // as parent window, so instead create it with a temporary placeholder
        // parent. Its parent is set as main window in UI process.
        initialParentWnd =
            ::CreateWindowEx(WS_EX_TOOLWINDOW, kClassNameCompositorInitalParent,
                             nullptr, WS_POPUP | WS_DISABLED, 0, 0, 1, 1,
                             nullptr, 0, GetModuleHandle(nullptr), 0);
        if (!initialParentWnd) {
          gfxCriticalNoteOnce << "Inital parent window failed "
                              << ::GetLastError();
          return;
        }

        DWORD extendedStyle = WS_EX_NOPARENTNOTIFY | WS_EX_NOREDIRECTIONBITMAP;

        if (!StaticPrefs::apz_windows_force_disable_direct_manipulation()) {
          extendedStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
        }

        compositorWnd = ::CreateWindowEx(
            extendedStyle, kClassNameCompositor, nullptr,
            WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0, 1, 1,
            initialParentWnd, 0, GetModuleHandle(nullptr), 0);
        if (!compositorWnd) {
          gfxCriticalNoteOnce << "Compositor window failed "
                              << ::GetLastError();
        }
      });

  Loop()->PostTask(runnable.forget());

  task.Wait();

  return WinCompositorWnds(compositorWnd, initialParentWnd);
}

/* static */
void WinCompositorWindowThread::DestroyCompositorWindow(
    WinCompositorWnds aWnds) {
  MOZ_ASSERT(aWnds.mCompositorWnd);
  MOZ_ASSERT(aWnds.mInitialParentWnd);
  MOZ_ASSERT(Loop());

  if (!Loop()) {
    return;
  }

  RefPtr runnable = NS_NewRunnableFunction(
      "WinCompositorWidget::CreateNativeWindow::Runnable", [aWnds]() {
        ::DestroyWindow(aWnds.mCompositorWnd);
        ::DestroyWindow(aWnds.mInitialParentWnd);
      });

  Loop()->PostTask(runnable.forget());
}

}  // namespace widget
}  // namespace mozilla