<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/kernels/internal/optimized/sse_tensor_utils_impl.h"

#ifdef __SSE4_1__

#include <emmintrin.h>  // SSE2
#include <smmintrin.h>  // SSE4.1
#include <tmmintrin.h>  // SSSE3

#include "tensorflow/lite/kernels/internal/compatibility.h"

namespace tflite {
namespace tensor_utils {
namespace {

// Elementwise multiply two i8x8 vectors to i16x8, add elements pairwise and
// accumulate result to a i32x4 accumulator.
//
// Shared by the inner loop of MatrixBatchVectorMultiplyAccumulate(int8) and
// SparseMatrixBatchVectorMultiplyAccumulate(int8).
//
// x86 SSE has no i8*i8 instruction (only a u8*i8), so we need to do sign
// extension to 16 bit and do i16*i16 multiplications. There is an instruction
// to sign-extend i8x8 => i16x8 from the lower half of the register (used here),
// but there is no direct way to sign-extend the high half, only multiple
// instructions (see _mm_cmpgt_epi8 and _mm_unpackhi_epi8). Bottom line is, it
// is actually cheaper to only to process 8 elements = 64b at a time.
static inline __m128i MatrixBatchVectorMultiplyAccumulateLoopBodySse(
    __m128i dotprod, __m128i a_8x8, __m128i b_8x8) {
  // Sign extend i8 => i16
  __m128i a_16x8 = _mm_cvtepi8_epi16(a_8x8);  // SSE4.1
  __m128i b_16x8 = _mm_cvtepi8_epi16(b_8x8);  // SSE4.1
  // sumprod[i] = a[2*i]*b[2*i] + a[2*i+1]*b[2*i+1] (i = 0..3)
  __m128i sumprod_32x4 = _mm_madd_epi16(a_16x8, b_16x8);  // SSE2
  // i32x4 + i32x4
  return _mm_add_epi32(dotprod, sumprod_32x4);  // SSE2
}

// Horizontally add 4 int32 values stored in a single XMM register to int32_t.
static inline int32_t ReduceInt32x4(__m128i acc) {
  acc = _mm_hadd_epi32(acc, acc);  // SSSE3
  // This second hadd could be only 64 bit, but 64 and 128 bit hadd has same
  // latency on most CPUs, and it costs more to move. (Moving can be no-op, but
  // nevertheless is an extra instruction occupying the decoder and I cache.)
  acc = _mm_hadd_epi32(acc, acc);  // SSSE3
  // SSE4.1 instrinsic, but actually translated to SSE2 instruction (due to
  // moving from 0th element).
  return _mm_extract_epi32(acc, 0);
}

}  // namespace

void SseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const int m_rows, const int m_cols,
    const int8_t* __restrict__ vectors, const float* scaling_factors,
    int n_batch, float* __restrict__ result, int result_stride) {
  static constexpr int kBlockSize = 8;
  for (int batch = 0; batch < n_batch; ++batch) {
    const float batch_scaling_factor = scaling_factors[batch];
    // Compute dot-product for every column.
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      // Get the address of the first element of the row.
      const int8_t* row_ptr = matrix + row * m_cols;

      // Initialize the dot product sum for the row to 0.
      __m128i dotprod_32x4 = _mm_setzero_si128();  // SSE2
      // For every block of kBlockSize 8-bit elements.
      int col = 0;
      for (; col < (m_cols & ~(kBlockSize - 1)); col += kBlockSize) {
        // See comment at MatrixBatchVectorMultiplyAccumulateLoopBodySse why to
        // load only 64 bits. _mm_loadl_epi64 requires SSE2.
        const __m128i vec_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(vectors + col));
        const __m128i row_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(row_ptr + col));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x8, row_8x8);
      }  // for col
      // Horizontally add the 4 intermediate sum values to get the final
      // dot-prod value for this row.
      int32_t sum = ReduceInt32x4(dotprod_32x4);

      // Postamble loop.
      for (; col < m_cols; ++col) {
        sum += row_ptr[col] * vectors[col];
      }  // for col

      *result += sum * batch_scaling_factor;
    }  // for row

    vectors += m_cols;
  }  // for batch
}

void SseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const int m_rows, const int m_cols,
    const int8_t* __restrict__ vectors, const float* scaling_factors,
    int n_batch, float* __restrict__ result, int result_stride,
    const float* per_channel_scale, const int32_t* input_offset) {
  static constexpr int kBlockSize = 8;
  for (int batch = 0; batch < n_batch; ++batch) {
    const float batch_scaling_factor = scaling_factors[batch];
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      const int8_t* row_ptr = matrix + row * m_cols;
      __m128i dotprod_32x4 = _mm_setzero_si128();  // SSE2
      __m128i row_sum_16x8 = _mm_setzero_si128();
      int col = 0;
      for (; col < (m_cols & ~(kBlockSize - 1)); col += kBlockSize) {
        const __m128i vec_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(vectors + col));
        const __m128i row_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(row_ptr + col));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x8, row_8x8);
        __m128i row_16x8 = _mm_cvtepi8_epi16(row_8x8);
        row_sum_16x8 = _mm_add_epi16(row_sum_16x8, row_16x8);
      }  // for col
      row_sum_16x8 = _mm_hadd_epi16(row_sum_16x8, row_sum_16x8);
      __m128i row_sum_32x4 = _mm_cvtepi16_epi32(row_sum_16x8);
      int32_t sum = ReduceInt32x4(dotprod_32x4);
      int32_t row_sum = ReduceInt32x4(row_sum_32x4);
      // Postamble loop.
      for (; col < m_cols; ++col) {
        sum += row_ptr[col] * vectors[col];
        row_sum += row_ptr[col];
      }  // for col
      sum -= row_sum * input_offset[batch];
      *result += sum * batch_scaling_factor * per_channel_scale[row];
    }  // for row
    vectors += m_cols;
  }  // for batch
}

void SseSparseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const uint8_t* ledger, const int m_rows,
    const int m_cols, const int8_t* __restrict__ vectors,
    const float* scaling_factors, int n_batch, float* __restrict__ result,
    int result_stride) {
  static const int kBlockSize = 16;
  TFLITE_DCHECK_EQ(m_cols % kBlockSize, 0);

  for (int batch = 0; batch < n_batch; ++batch, vectors += m_cols) {
    const float batch_scaling_factor = scaling_factors[batch];
    const uint8_t* ledger_ptr = ledger;
    const int8_t* row_ptr = matrix;
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      // Initialize the dot product sum for the row to 0.
      __m128i dotprod_32x4 = _mm_setzero_si128();
      int num_nonzero_blocks = *ledger_ptr++;
      for (int i = 0; i < num_nonzero_blocks; i++) {
        const int col_index = *ledger_ptr++ * kBlockSize;
        // With sparse models, we assume the block size is 16, we can't change
        // it to 8 here to better fit SSE (see dense version). Instead, do the
        // int8x8_t computation twice.
        __m128i vec_8x8 = _mm_loadl_epi64(
            reinterpret_cast<const __m128i*>(vectors + col_index));
        __m128i row_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(row_ptr));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x8, row_8x8);
        vec_8x8 = _mm_loadl_epi64(
            reinterpret_cast<const __m128i*>(vectors + col_index + 8));
        row_8x8 =
            _mm_loadl_epi64(reinterpret_cast<const __m128i*>(row_ptr + 8));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x8, row_8x8);
        row_ptr += kBlockSize;
      }
      // Horizontally add the 4 intermediate sum values to get the final
      // dot-prod value for this row.
      int32_t dotprod = ReduceInt32x4(dotprod_32x4);

      *result += dotprod * batch_scaling_factor;
    }  // for row
  }    // for batch
}

}  // namespace tensor_utils
}  // namespace tflite

#endif  // __SSE4_1__
<commit_msg>Optimize SSE version of hybrid flavors of MatrixBatchVectorMultiplyAccumulate: Use pmaddubsw to multiply-accumulate 16 elements at a time (previously 8).<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/kernels/internal/optimized/sse_tensor_utils_impl.h"

#ifdef __SSSE3__

#include <emmintrin.h>  // SSE2
#include <tmmintrin.h>  // SSSE3

#include "tensorflow/lite/kernels/internal/compatibility.h"

namespace tflite {
namespace tensor_utils {
namespace {

// Elementwise multiply two i8x16 vectors to i16x8, add elements pairwise and
// accumulate result to a i32x4 accumulator.
//
// Shared by the inner loop of MatrixBatchVectorMultiplyAccumulate(int8) and
// SparseMatrixBatchVectorMultiplyAccumulate(int8).
static inline __m128i MatrixBatchVectorMultiplyAccumulateLoopBodySse(
    __m128i dotprod, __m128i a_8x16, __m128i b_8x16) {
  // Transfer sign from 'a' to 'b', as _mm_maddubs_epi16 treats 'a' unsigned.
  b_8x16 = _mm_sign_epi8(b_8x16, a_8x16);
  a_8x16 = _mm_abs_epi8(a_8x16);
  // sumprod[i] = a[2*i]*b[2*i] + a[2*i+1]*b[2*i+1] (i = 0..7)
  __m128i sumprod_16x8 = _mm_maddubs_epi16(a_8x16, b_8x16);
  // sumprod[i] = sumprod[2*i]*1 + sumprod[2*i+1]*1 (i = 0..3)
  __m128i sumprod_32x4 = _mm_madd_epi16(sumprod_16x8, _mm_set1_epi16(1));
  // accumlator += sumprod
  return _mm_add_epi32(dotprod, sumprod_32x4);
}

// Horizontally add 4 int32 values stored in a single XMM register to int32_t.
static inline int32_t ReduceInt32x4(__m128i acc) {
  acc = _mm_hadd_epi32(acc, acc);
  // This second hadd could be only 64 bit, but 64 and 128 bit hadd has same
  // latency on most CPUs, and it costs more to move. (Moving can be no-op, but
  // nevertheless is an extra instruction occupying the decoder and I cache.)
  acc = _mm_hadd_epi32(acc, acc);
  return _mm_cvtsi128_si32(acc);
}

}  // namespace

void SseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const int m_rows, const int m_cols,
    const int8_t* __restrict__ vectors, const float* scaling_factors,
    int n_batch, float* __restrict__ result, int result_stride) {
  static constexpr int kBlockSize = 16;
  for (int batch = 0; batch < n_batch; ++batch) {
    const float batch_scaling_factor = scaling_factors[batch];
    // Compute dot-product for every column.
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      // Get the address of the first element of the row.
      const int8_t* row_ptr = matrix + row * m_cols;

      // Initialize the dot product sum for the row to 0.
      __m128i dotprod_32x4 = _mm_setzero_si128();
      // For every block of kBlockSize 8-bit elements.
      int col = 0;
      for (; col < (m_cols & ~(kBlockSize - 1)); col += kBlockSize) {
        const __m128i vec_8x16 =
            _mm_loadu_si128(reinterpret_cast<const __m128i*>(vectors + col));
        const __m128i row_8x16 =
            _mm_loadu_si128(reinterpret_cast<const __m128i*>(row_ptr + col));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x16, row_8x16);
      }  // for col
      // Horizontally add the 4 intermediate sum values to get the final
      // dot-prod value for this row.
      int32_t sum = ReduceInt32x4(dotprod_32x4);

      // Postamble loop.
      for (; col < m_cols; ++col) {
        sum += row_ptr[col] * vectors[col];
      }  // for col

      *result += sum * batch_scaling_factor;
    }  // for row

    vectors += m_cols;
  }  // for batch
}

void SseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const int m_rows, const int m_cols,
    const int8_t* __restrict__ vectors, const float* scaling_factors,
    int n_batch, float* __restrict__ result, int result_stride,
    const float* per_channel_scale, const int32_t* input_offset) {
  static constexpr int kBlockSize = 16;
  for (int batch = 0; batch < n_batch; ++batch) {
    const float batch_scaling_factor = scaling_factors[batch];
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      const int8_t* row_ptr = matrix + row * m_cols;
      __m128i dotprod_32x4 = _mm_setzero_si128();
      __m128i row_sum_16x8 = _mm_setzero_si128();
      int col = 0;
      for (; col < (m_cols & ~(kBlockSize - 1)); col += kBlockSize) {
        const __m128i vec_8x16 =
            _mm_loadu_si128(reinterpret_cast<const __m128i*>(vectors + col));
        const __m128i row_8x16 =
            _mm_loadu_si128(reinterpret_cast<const __m128i*>(row_ptr + col));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x16, row_8x16);

        // Pairwise add 16x 8-bit values; equivalently, multipy-add with 1.
        // Result is 8x 16-bit values.
        const __m128i row_16x8 = _mm_maddubs_epi16(_mm_set1_epi8(1), row_8x16);
        row_sum_16x8 = _mm_add_epi16(row_sum_16x8, row_16x8);
      }  // for col
      // Pairwise add 8x 16-bit values; equivalently, multipy-add with 1.
      // Result is 4x 32-bit values.
      const __m128i row_sum_32x4 =
          _mm_madd_epi16(row_sum_16x8, _mm_set1_epi16(1));
      int32_t sum = ReduceInt32x4(dotprod_32x4);
      int32_t row_sum = ReduceInt32x4(row_sum_32x4);
      // Postamble loop.
      for (; col < m_cols; ++col) {
        sum += row_ptr[col] * vectors[col];
        row_sum += row_ptr[col];
      }  // for col
      sum -= row_sum * input_offset[batch];
      *result += sum * batch_scaling_factor * per_channel_scale[row];
    }  // for row
    vectors += m_cols;
  }  // for batch
}

void SseSparseMatrixBatchVectorMultiplyAccumulate(
    const int8_t* __restrict__ matrix, const uint8_t* ledger, const int m_rows,
    const int m_cols, const int8_t* __restrict__ vectors,
    const float* scaling_factors, int n_batch, float* __restrict__ result,
    int result_stride) {
  static const int kBlockSize = 16;
  TFLITE_DCHECK_EQ(m_cols % kBlockSize, 0);

  for (int batch = 0; batch < n_batch; ++batch, vectors += m_cols) {
    const float batch_scaling_factor = scaling_factors[batch];
    const uint8_t* ledger_ptr = ledger;
    const int8_t* row_ptr = matrix;
    for (int row = 0; row < m_rows; ++row, result += result_stride) {
      // Initialize the dot product sum for the row to 0.
      __m128i dotprod_32x4 = _mm_setzero_si128();
      int num_nonzero_blocks = *ledger_ptr++;
      for (int i = 0; i < num_nonzero_blocks; i++) {
        const int col_index = *ledger_ptr++ * kBlockSize;
        const __m128i vec_8x16 = _mm_loadu_si128(
            reinterpret_cast<const __m128i*>(vectors + col_index));
        const __m128i row_8x16 =
            _mm_loadu_si128(reinterpret_cast<const __m128i*>(row_ptr));
        dotprod_32x4 = MatrixBatchVectorMultiplyAccumulateLoopBodySse(
            dotprod_32x4, vec_8x16, row_8x16);
        row_ptr += kBlockSize;
      }  // for col
      // Horizontally add the 4 intermediate sum values to get the final
      // dot-prod value for this row.
      int32_t dotprod = ReduceInt32x4(dotprod_32x4);

      *result += dotprod * batch_scaling_factor;
    }  // for row
  }    // for batch
}

}  // namespace tensor_utils
}  // namespace tflite

#endif  // __SSSE3__
<|endoftext|>


<commit_before>//===--- TerminalDisplayWin.h - Output To Windows Console -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a Windows console
//  i.e. cmd.exe.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#ifdef _WIN32
#include "textinput/TerminalDisplayWin.h"
#include "textinput/Color.h"

#include <assert.h>

namespace textinput {
  TerminalDisplayWin::TerminalDisplayWin():
    TerminalDisplay(false), fStartLine(0), fIsAttached(false),
    fDefaultAttributes(0), fOldCodePage(::GetConsoleOutputCP()) {
    DWORD mode;
    SetIsTTY(::GetConsoleMode(::GetStdHandle(STD_INPUT_HANDLE), &mode) != 0);

    fOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
    bool isConsole = ::GetConsoleMode(fOut, &fOldMode) != 0;
    if (!isConsole) {
      // Prevent redirection from stealing our console handle,
      // simply open our own.
      fOut = ::CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
      ::GetConsoleMode(fOut, &fOldMode);
    } else {
      ::SetConsoleOutputCP(65001); // Force UTF-8 output
    }
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ::GetConsoleScreenBufferInfo(fOut, &csbi);
    fDefaultAttributes = csbi.wAttributes;
    assert(fDefaultAttributes != 0 && "~TerminalDisplayWin broken");
    fMyMode = fOldMode | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
    HandleResizeEvent();
  }

  TerminalDisplayWin::~TerminalDisplayWin() {
    if (fDefaultAttributes) {
      ::SetConsoleTextAttribute(fOut, fDefaultAttributes);
      // We allocated CONOUT$:
      CloseHandle(fOut);
    } else
      ::SetConsoleOutputCP(fOldCodePage);
  }

  void
  TerminalDisplayWin::HandleResizeEvent() {
    if (IsTTY()) {
      CONSOLE_SCREEN_BUFFER_INFO Info;
      if (!::GetConsoleScreenBufferInfo(fOut, &Info)) {
        ShowError("resize / getting console info");
        return;
      }
      SetWidth(Info.dwSize.X);
    }
  }

  void
  TerminalDisplayWin::SetColor(char CIdx, const Color& C) {
    WORD Attribs = 0;
    // There is no underline since DOS has died.
    if (C.fModifiers & Color::kModUnderline) Attribs |= BACKGROUND_INTENSITY;
    if (C.fModifiers & Color::kModBold) Attribs |= FOREGROUND_INTENSITY;
    if (C.fR > 64) Attribs |= FOREGROUND_RED;
    if (C.fG > 64) Attribs |= FOREGROUND_GREEN;
    if (C.fB > 64) Attribs |= FOREGROUND_BLUE;
    // if CIdx is 0 (default) then use the original console text color
    // (instead of the greyish one)
    if (CIdx == 0)
      ::SetConsoleTextAttribute(fOut, fDefaultAttributes);
    else
      ::SetConsoleTextAttribute(fOut, Attribs);
  }

  void
  TerminalDisplayWin::CheckCursorPos() {
    if (!IsTTY()) return;
    // Did something print something on the screen?
    // I.e. did the cursor move?
    CONSOLE_SCREEN_BUFFER_INFO CSI;
    if (::GetConsoleScreenBufferInfo(fOut, &CSI)) {
      if (CSI.dwCursorPosition.X != fWritePos.fCol
        || CSI.dwCursorPosition.Y != fWritePos.fLine + fStartLine) {
        fStartLine = CSI.dwCursorPosition.Y;
        if (CSI.dwCursorPosition.X) {
          // fStartLine may be a couple of lines higher (or more precisely
          // the number of written lines higher)
          fStartLine -= fWritePos.fLine;
        }
        fWritePos.fCol = 0;
        fWritePos.fLine = 0;
      }
    }
  }

  void
  TerminalDisplayWin::Move(Pos P) {
    CheckCursorPos();
    MoveInternal(P);
    fWritePos = P;
  }

  void
  TerminalDisplayWin::MoveInternal(Pos P) {
    if (IsTTY()) {
      COORD C = {P.fCol, P.fLine + fStartLine};
      ::SetConsoleCursorPosition(fOut, C);
    }
  }

  void
  TerminalDisplayWin::MoveFront() {
    Pos P(fWritePos);
    P.fCol = 0;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveUp(size_t nLines /* = 1 */) {
    Pos P(fWritePos);
    --P.fLine;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveDown(size_t nLines /* = 1 */) {
    Pos P(fWritePos);
    ++P.fLine;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveRight(size_t nCols /* = 1 */) {
    Pos P(fWritePos);
    ++P.fCol;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveLeft(size_t nCols /* = 1 */) {
    Pos P(fWritePos);
    --P.fCol;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::EraseToRight() {
    DWORD NumWritten;
    COORD C = {fWritePos.fCol, fWritePos.fLine + fStartLine};
    ::FillConsoleOutputCharacterA(fOut, ' ', GetWidth() - C.X, C,
      &NumWritten);
    // It wraps, so move up and reset WritePos:
    //MoveUp();
    //++WritePos.Line;
  }

  void
  TerminalDisplayWin::WriteRawString(const char *text, size_t len) {
    DWORD NumWritten = 0;
    if (IsTTY()) {
      WriteConsoleA(fOut, text, (DWORD) len, &NumWritten, NULL);
    } else {
      WriteFile(fOut, text, (DWORD) len, &NumWritten, NULL);
    }
    if (NumWritten != len) {
      ShowError("writing to output");
    }
  }

  void
  TerminalDisplayWin::Attach() {
    // set to noecho
    if (fIsAttached || !IsTTY()) return;
    if (!::SetConsoleMode(fOut, fMyMode)) {
      ShowError("attaching to console output");
    }
    CONSOLE_SCREEN_BUFFER_INFO Info;
    if (!::GetConsoleScreenBufferInfo(fOut, &Info)) {
      ShowError("attaching / getting console info");
    } else {
      fStartLine = Info.dwCursorPosition.Y;
      if (Info.dwCursorPosition.X) {
        // Whooa - where are we?! Newline and cross fingers:
        WriteRawString("\n", 1);
        ++fStartLine;
      }
    }
    fIsAttached = true;
  }

  void
  TerminalDisplayWin::Detach() {
    if (!fIsAttached || !IsTTY()) return;
    if (!SetConsoleMode(fOut, fOldMode)) {
      ShowError("detaching to console output");
    }
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  void
  TerminalDisplayWin::ShowError(const char* Where) const {
    DWORD Err = GetLastError();
    LPVOID MsgBuf = 0;
    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
      FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPSTR) &MsgBuf, 0, NULL);

    printf("Error %d in textinput::TerminalDisplayWin %s: %s\n", Err, Where, MsgBuf);
    LocalFree(MsgBuf);
  }

}

#endif // ifdef _WIN32
<commit_msg>disable unicode (UTF-8) in the console for the time being, since it causes problems on Windows 10<commit_after>//===--- TerminalDisplayWin.h - Output To Windows Console -------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a Windows console
//  i.e. cmd.exe.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#ifdef _WIN32
#include "textinput/TerminalDisplayWin.h"
#include "textinput/Color.h"

#include <assert.h>

namespace textinput {
  TerminalDisplayWin::TerminalDisplayWin():
    TerminalDisplay(false), fStartLine(0), fIsAttached(false),
    fDefaultAttributes(0), fOldCodePage(::GetConsoleOutputCP()) {
    DWORD mode;
    SetIsTTY(::GetConsoleMode(::GetStdHandle(STD_INPUT_HANDLE), &mode) != 0);

    fOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
    bool isConsole = ::GetConsoleMode(fOut, &fOldMode) != 0;
    if (!isConsole) {
      // Prevent redirection from stealing our console handle,
      // simply open our own.
      fOut = ::CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
      ::GetConsoleMode(fOut, &fOldMode);
    } else {
      // disable unicode (UTF-8) for the time being, since it causes
      // problems on Windows 10
      //::SetConsoleOutputCP(65001); // Force UTF-8 output
    }
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ::GetConsoleScreenBufferInfo(fOut, &csbi);
    fDefaultAttributes = csbi.wAttributes;
    assert(fDefaultAttributes != 0 && "~TerminalDisplayWin broken");
    fMyMode = fOldMode | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
    HandleResizeEvent();
  }

  TerminalDisplayWin::~TerminalDisplayWin() {
    if (fDefaultAttributes) {
      ::SetConsoleTextAttribute(fOut, fDefaultAttributes);
      // We allocated CONOUT$:
      CloseHandle(fOut);
    }
    ::SetConsoleOutputCP(fOldCodePage);
  }

  void
  TerminalDisplayWin::HandleResizeEvent() {
    if (IsTTY()) {
      CONSOLE_SCREEN_BUFFER_INFO Info;
      if (!::GetConsoleScreenBufferInfo(fOut, &Info)) {
        ShowError("resize / getting console info");
        return;
      }
      SetWidth(Info.dwSize.X);
    }
  }

  void
  TerminalDisplayWin::SetColor(char CIdx, const Color& C) {
    WORD Attribs = 0;
    // There is no underline since DOS has died.
    if (C.fModifiers & Color::kModUnderline) Attribs |= BACKGROUND_INTENSITY;
    if (C.fModifiers & Color::kModBold) Attribs |= FOREGROUND_INTENSITY;
    if (C.fR > 64) Attribs |= FOREGROUND_RED;
    if (C.fG > 64) Attribs |= FOREGROUND_GREEN;
    if (C.fB > 64) Attribs |= FOREGROUND_BLUE;
    // if CIdx is 0 (default) then use the original console text color
    // (instead of the greyish one)
    if (CIdx == 0)
      ::SetConsoleTextAttribute(fOut, fDefaultAttributes);
    else
      ::SetConsoleTextAttribute(fOut, Attribs);
  }

  void
  TerminalDisplayWin::CheckCursorPos() {
    if (!IsTTY()) return;
    // Did something print something on the screen?
    // I.e. did the cursor move?
    CONSOLE_SCREEN_BUFFER_INFO CSI;
    if (::GetConsoleScreenBufferInfo(fOut, &CSI)) {
      if (CSI.dwCursorPosition.X != fWritePos.fCol
        || CSI.dwCursorPosition.Y != fWritePos.fLine + fStartLine) {
        fStartLine = CSI.dwCursorPosition.Y;
        if (CSI.dwCursorPosition.X) {
          // fStartLine may be a couple of lines higher (or more precisely
          // the number of written lines higher)
          fStartLine -= fWritePos.fLine;
        }
        fWritePos.fCol = 0;
        fWritePos.fLine = 0;
      }
    }
  }

  void
  TerminalDisplayWin::Move(Pos P) {
    CheckCursorPos();
    MoveInternal(P);
    fWritePos = P;
  }

  void
  TerminalDisplayWin::MoveInternal(Pos P) {
    if (IsTTY()) {
      COORD C = {P.fCol, P.fLine + fStartLine};
      ::SetConsoleCursorPosition(fOut, C);
    }
  }

  void
  TerminalDisplayWin::MoveFront() {
    Pos P(fWritePos);
    P.fCol = 0;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveUp(size_t nLines /* = 1 */) {
    Pos P(fWritePos);
    --P.fLine;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveDown(size_t nLines /* = 1 */) {
    Pos P(fWritePos);
    ++P.fLine;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveRight(size_t nCols /* = 1 */) {
    Pos P(fWritePos);
    ++P.fCol;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::MoveLeft(size_t nCols /* = 1 */) {
    Pos P(fWritePos);
    --P.fCol;
    MoveInternal(P);
  }

  void
  TerminalDisplayWin::EraseToRight() {
    DWORD NumWritten;
    COORD C = {fWritePos.fCol, fWritePos.fLine + fStartLine};
    ::FillConsoleOutputCharacter(fOut, ' ', GetWidth() - C.X, C,
      &NumWritten);
    // It wraps, so move up and reset WritePos:
    //MoveUp();
    //++WritePos.Line;
  }

  void
  TerminalDisplayWin::WriteRawString(const char *text, size_t len) {
    DWORD NumWritten = 0;
    if (IsTTY()) {
      WriteConsole(fOut, text, (DWORD) len, &NumWritten, NULL);
    } else {
      WriteFile(fOut, text, (DWORD) len, &NumWritten, NULL);
    }
    if (NumWritten != len) {
      ShowError("writing to output");
    }
  }

  void
  TerminalDisplayWin::Attach() {
    // set to noecho
    if (fIsAttached || !IsTTY()) return;
    if (!::SetConsoleMode(fOut, fMyMode)) {
      ShowError("attaching to console output");
    }
    CONSOLE_SCREEN_BUFFER_INFO Info;
    if (!::GetConsoleScreenBufferInfo(fOut, &Info)) {
      ShowError("attaching / getting console info");
    } else {
      fStartLine = Info.dwCursorPosition.Y;
      if (Info.dwCursorPosition.X) {
        // Whooa - where are we?! Newline and cross fingers:
        WriteRawString("\n", 1);
        ++fStartLine;
      }
    }
    fIsAttached = true;
  }

  void
  TerminalDisplayWin::Detach() {
    if (!fIsAttached || !IsTTY()) return;
    if (!SetConsoleMode(fOut, fOldMode)) {
      ShowError("detaching to console output");
    }
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  void
  TerminalDisplayWin::ShowError(const char* Where) const {
    DWORD Err = GetLastError();
    LPVOID MsgBuf = 0;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
      FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &MsgBuf, 0, NULL);

    printf("Error %d in textinput::TerminalDisplayWin %s: %s\n", Err, Where, MsgBuf);
    LocalFree(MsgBuf);
  }

}

#endif // ifdef _WIN32
<|endoftext|>


<commit_before><commit_msg>[Android] Allow constructor of Notifications on Android.<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRInterface.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2009 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkRInterface.h"

#undef HAVE_UINTPTR_T
#ifdef HAVE_VTK_UINTPTR_T
#define HAVE_UINTPTR_T HAVE_VTK_UINTPTR_T
#include <stdint.h>
#endif

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkDataArray.h"
#include "vtkRAdapter.h"

vtkStandardNewMacro(vtkRInterface);

#include "R.h"
#include "Rmath.h"
#include "Rembedded.h"
#include "Rversion.h"
#include "Rdefines.h"

#ifndef WIN32
#define CSTACK_DEFNS
#define R_INTERFACE_PTRS
#include "Rinterface.h"
#endif

#include "R_ext/Parse.h"

#include "vtksys/SystemTools.hxx"

class vtkImplementationRSingleton
{
public:
  static vtkImplementationRSingleton* Instance();

  void InitializeR()
  {

  if(this->Rinitialized)
    {
    this->refcount++;
    return;
    }

#ifndef WIN32
    R_SignalHandlers = 0;
#endif

#ifdef CSTACK_DEFNS
    R_CStackLimit = (uintptr_t)-1;
#endif

  const char* path = vtksys::SystemTools::GetEnv("R_HOME");
  if (!path)
    {
    std::string newPath = "R_HOME=";
    newPath=newPath+VTK_R_HOME;
    vtksys::SystemTools::PutEnv(newPath.c_str());
    }
    const char* path2 = vtksys::SystemTools::GetEnv("R_HOME");
    char *R_argv[]= {"vtkRInterface", "--gui=none", "--no-save", "--no-readline", "--silent"};
    Rf_initEmbeddedR(sizeof(R_argv)/sizeof(R_argv[0]), R_argv);

    this->Rinitialized = 1;
    this->refcount++;

    vtkstd::string  rcommand;
    rcommand.append("f<-file(paste(tempdir(), \"/Routput.txt\", sep = \"\"), open=\"wt+\")\nsink(f)\n");
    this->tmpFilePath.clear();
    this->tmpFilePath.append(R_TempDir);
#ifdef WIN32
    this->tmpFilePath.append("\\Routput.txt");
#else
    this->tmpFilePath.append("/Routput.txt");
#endif

    ParseStatus status;
    SEXP cmdSexp, cmdexpr = R_NilValue;
    int error;

    PROTECT(cmdSexp = allocVector(STRSXP, 1));
    SET_STRING_ELT(cmdSexp, 0, mkChar(rcommand.c_str()));

    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
    for(int i = 0; i < length(cmdexpr); i++)
      {
      R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
      }
    UNPROTECT(2);

  };

  const char* GetROutputFilePath()
    {
    return tmpFilePath.c_str();
    };

  void CloseR()
    {
    this->refcount--;
    };

protected:

  ~vtkImplementationRSingleton();

  vtkImplementationRSingleton();

  vtkImplementationRSingleton(const vtkImplementationRSingleton&);

  vtkImplementationRSingleton& operator=(const vtkImplementationRSingleton&);

private:

  vtkstd::string tmpFilePath;
  int refcount;
  int Rinitialized;
  static vtkImplementationRSingleton* ins;
  static void shutdownR(void);

};

void vtkImplementationRSingleton::shutdownR(void)
{
   if(ins)
     {
     delete ins;
     }
}

vtkImplementationRSingleton* vtkImplementationRSingleton::Instance()
{

  if(ins == 0)
    {
    ins = new vtkImplementationRSingleton;

    // Setup atexit() function to shutdown R interpreter when application exits
    atexit(shutdownR);
    }

  ins->InitializeR();
  return(ins);

}

vtkImplementationRSingleton::~vtkImplementationRSingleton()
{

  R_CleanTempDir();
  Rf_endEmbeddedR(0);

}

vtkImplementationRSingleton::vtkImplementationRSingleton()
{

  this->refcount = 0;
  this->Rinitialized = 0;

}

vtkImplementationRSingleton* vtkImplementationRSingleton::ins = 0;

//----------------------------------------------------------------------------
vtkRInterface::vtkRInterface()
{

  this->rs = vtkImplementationRSingleton::Instance();
  this->buffer = 0;
  this->buffer_size = 0;
  this->vra = vtkRAdapter::New();

}

//----------------------------------------------------------------------------
vtkRInterface::~vtkRInterface()
{

  this->rs->CloseR();
  this->vra->Delete();

}

int vtkRInterface::EvalRscript(const char *string, bool showRoutput)
{

  ParseStatus status;
  SEXP cmdSexp, cmdexpr = R_NilValue;
  SEXP ans;
  int i;
  int error;

  PROTECT(cmdSexp = allocVector(STRSXP, 1));
  SET_STRING_ELT(cmdSexp, 0, mkChar(string));

  cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
  switch (status)
    {
    case PARSE_OK:
      for(i = 0; i < length(cmdexpr); i++)
        {
        ans = R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
        if (error)
          {
          return 1;
          }
        if(showRoutput)
          {
          PrintValue(ans);
          }
        }
      break;
    case PARSE_INCOMPLETE:
      vtkErrorMacro(<<"R parse status is PARSE_INCOMPLETE");
      /* need to read another line */
      break;
    case PARSE_NULL:
      vtkErrorMacro(<<"R parse status is PARSE_NULL");
      return 1;
      break;
    case PARSE_ERROR:
      vtkErrorMacro(<<"R parse status is PARSE_ERROR");
      return 1;
      break;
    case PARSE_EOF:
      vtkErrorMacro(<<"R parse status is PARSE_EOF");
      break;
    default:
      vtkErrorMacro(<<"R parse status is NOT DOCUMENTED");
      return 1;
      break;
    }
  UNPROTECT(2);
  this->FillOutputBuffer();
  return 0;

}

int vtkRInterface::EvalRcommand(const char *funcName, int param)
{

  SEXP e;
  SEXP arg;
  int errorOccurred;

  PROTECT(arg = allocVector(INTSXP, 1));
  INTEGER(arg)[0]  = param;
  PROTECT(e = lang2(install(funcName), arg));

  R_tryEval(e, R_GlobalEnv, &errorOccurred);

  UNPROTECT(2);
  return(errorOccurred);

}

void vtkRInterface::AssignVTKDataArrayToRVariable(vtkDataArray* da, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKDataArrayToR(da);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

void vtkRInterface::AssignVTKArrayToRVariable(vtkArray* da, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKArrayToR(da);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

vtkDataArray* vtkRInterface::AssignRVariableToVTKDataArray(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKDataArray(s));
  else
    return(0);

}

vtkArray* vtkRInterface::AssignRVariableToVTKArray(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKArray(s));
  else
    return(0);

}

vtkTable* vtkRInterface::AssignRVariableToVTKTable(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKTable(s));
  else
    return(0);

}

void vtkRInterface::AssignVTKTableToRVariable(vtkTable* table, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKTableToR(table);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

int vtkRInterface::OutputBuffer(char* p, int n)
{

  this->buffer = p;
  this->buffer_size = n;
  if(this->buffer && (this->buffer_size > 0) )
    {
    this->buffer[0] = '\0';
    }
  return(1);

}

int vtkRInterface::FillOutputBuffer()
{

  FILE *fp;
  long len;

  if(this->buffer && (this->buffer_size > 0) )
    {
    fp = fopen(this->rs->GetROutputFilePath(),"rb");

    if(!fp)
      {
      vtkErrorMacro(<<"Can't open input file named " << this->rs->GetROutputFilePath());
      return(0);
      }

    fseek(fp,0,SEEK_END);
    len = ftell(fp);

    if(len == 0)
      {
      return(1);
      }

    if(len >= this->buffer_size)
      {
      fseek(fp,len-this->buffer_size+1,SEEK_SET);
      fread(this->buffer,1,this->buffer_size-1,fp);
      this->buffer[this->buffer_size-1] = '\0';
      }
    else
      {
      fseek(fp,0,SEEK_SET);
      fread(this->buffer,1,len,fp);
      this->buffer[len] = '\0';
      }

    fclose(fp);

    return(1);

    }
  else
    {
    return(0);
    }

}

void vtkRInterface::PrintSelf(ostream& os, vtkIndent indent)
{

  this->Superclass::PrintSelf(os, indent);

  os << indent << "buffer_size: " << this->buffer_size << endl;
  os << indent << "buffer: " << (this->buffer ? this->buffer : "NULL") << endl;

  if(this->vra)
    {
    this->vra->PrintSelf(os, indent);
    }

}

<commit_msg>BUG: Fixing stack problem with web interface<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRInterface.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2009 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkRInterface.h"

#undef HAVE_UINTPTR_T
#ifdef HAVE_VTK_UINTPTR_T
#define HAVE_UINTPTR_T HAVE_VTK_UINTPTR_T
#include <stdint.h>
#endif

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkDataArray.h"
#include "vtkRAdapter.h"

vtkStandardNewMacro(vtkRInterface);

#include "R.h"
#include "Rmath.h"
#include "Rembedded.h"
#include "Rversion.h"
#include "Rdefines.h"

#ifndef WIN32
#define CSTACK_DEFNS
#define R_INTERFACE_PTRS
#include "Rinterface.h"
#endif

#include "R_ext/Parse.h"

#include "vtksys/SystemTools.hxx"

class vtkImplementationRSingleton
{
public:
  static vtkImplementationRSingleton* Instance();

  void InitializeR()
  {

  if(this->Rinitialized)
    {
    this->refcount++;
    return;
    }

#ifndef WIN32
    R_SignalHandlers = 0;
#endif

  const char* path = vtksys::SystemTools::GetEnv("R_HOME");
  if (!path)
    {
    std::string newPath = "R_HOME=";
    newPath=newPath+VTK_R_HOME;
    vtksys::SystemTools::PutEnv(newPath.c_str());
    }
    const char* path2 = vtksys::SystemTools::GetEnv("R_HOME");
    char *R_argv[]= {"vtkRInterface", "--gui=none", "--no-save", "--no-readline", "--silent"};

    Rf_initialize_R(sizeof(R_argv)/sizeof(R_argv[0]), R_argv);

#ifdef CSTACK_DEFNS
    R_CStackLimit = (uintptr_t)-1;
#endif

    R_Interactive = static_cast<Rboolean>(TRUE);
    setup_Rmainloop();

    this->Rinitialized = 1;
    this->refcount++;

    vtkstd::string  rcommand;
    rcommand.append("f<-file(paste(tempdir(), \"/Routput.txt\", sep = \"\"), open=\"wt+\")\nsink(f)\n");
    this->tmpFilePath.clear();
    this->tmpFilePath.append(R_TempDir);
#ifdef WIN32
    this->tmpFilePath.append("\\Routput.txt");
#else
    this->tmpFilePath.append("/Routput.txt");
#endif

    ParseStatus status;
    SEXP cmdSexp, cmdexpr = R_NilValue;
    int error;

    PROTECT(cmdSexp = allocVector(STRSXP, 1));
    SET_STRING_ELT(cmdSexp, 0, mkChar(rcommand.c_str()));

    cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
    for(int i = 0; i < length(cmdexpr); i++)
      {
      R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
      }
    UNPROTECT(2);

  };

  const char* GetROutputFilePath()
    {
    return tmpFilePath.c_str();
    };

  void CloseR()
    {
    this->refcount--;
    };

protected:

  ~vtkImplementationRSingleton();

  vtkImplementationRSingleton();

  vtkImplementationRSingleton(const vtkImplementationRSingleton&);

  vtkImplementationRSingleton& operator=(const vtkImplementationRSingleton&);

private:

  vtkstd::string tmpFilePath;
  int refcount;
  int Rinitialized;
  static vtkImplementationRSingleton* ins;
  static void shutdownR(void);

};

void vtkImplementationRSingleton::shutdownR(void)
{
   if(ins)
     {
     delete ins;
     }
}

vtkImplementationRSingleton* vtkImplementationRSingleton::Instance()
{

  if(ins == 0)
    {
    ins = new vtkImplementationRSingleton;

    // Setup atexit() function to shutdown R interpreter when application exits
    atexit(shutdownR);
    }

  ins->InitializeR();
  return(ins);

}

vtkImplementationRSingleton::~vtkImplementationRSingleton()
{

  R_CleanTempDir();
  Rf_endEmbeddedR(0);

}

vtkImplementationRSingleton::vtkImplementationRSingleton()
{

  this->refcount = 0;
  this->Rinitialized = 0;

}

vtkImplementationRSingleton* vtkImplementationRSingleton::ins = 0;

//----------------------------------------------------------------------------
vtkRInterface::vtkRInterface()
{

  this->rs = vtkImplementationRSingleton::Instance();
  this->buffer = 0;
  this->buffer_size = 0;
  this->vra = vtkRAdapter::New();

}

//----------------------------------------------------------------------------
vtkRInterface::~vtkRInterface()
{

  this->rs->CloseR();
  this->vra->Delete();

}

int vtkRInterface::EvalRscript(const char *string, bool showRoutput)
{

  ParseStatus status;
  SEXP cmdSexp, cmdexpr = R_NilValue;
  SEXP ans;
  int i;
  int error;

  PROTECT(cmdSexp = allocVector(STRSXP, 1));
  SET_STRING_ELT(cmdSexp, 0, mkChar(string));

  cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
  switch (status)
    {
    case PARSE_OK:
      for(i = 0; i < length(cmdexpr); i++)
        {
        ans = R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
        if (error)
          {
          return 1;
          }
        if(showRoutput)
          {
          PrintValue(ans);
          }
        }
      break;
    case PARSE_INCOMPLETE:
      vtkErrorMacro(<<"R parse status is PARSE_INCOMPLETE");
      /* need to read another line */
      break;
    case PARSE_NULL:
      vtkErrorMacro(<<"R parse status is PARSE_NULL");
      return 1;
      break;
    case PARSE_ERROR:
      vtkErrorMacro(<<"R parse status is PARSE_ERROR");
      return 1;
      break;
    case PARSE_EOF:
      vtkErrorMacro(<<"R parse status is PARSE_EOF");
      break;
    default:
      vtkErrorMacro(<<"R parse status is NOT DOCUMENTED");
      return 1;
      break;
    }
  UNPROTECT(2);
  this->FillOutputBuffer();
  return 0;

}

int vtkRInterface::EvalRcommand(const char *funcName, int param)
{

  SEXP e;
  SEXP arg;
  int errorOccurred;

  PROTECT(arg = allocVector(INTSXP, 1));
  INTEGER(arg)[0]  = param;
  PROTECT(e = lang2(install(funcName), arg));

  R_tryEval(e, R_GlobalEnv, &errorOccurred);

  UNPROTECT(2);
  return(errorOccurred);

}

void vtkRInterface::AssignVTKDataArrayToRVariable(vtkDataArray* da, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKDataArrayToR(da);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

void vtkRInterface::AssignVTKArrayToRVariable(vtkArray* da, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKArrayToR(da);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

vtkDataArray* vtkRInterface::AssignRVariableToVTKDataArray(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKDataArray(s));
  else
    return(0);

}

vtkArray* vtkRInterface::AssignRVariableToVTKArray(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKArray(s));
  else
    return(0);

}

vtkTable* vtkRInterface::AssignRVariableToVTKTable(const char* RVariableName)
{

  SEXP s;

  s = findVar(install(RVariableName), R_GlobalEnv);

  if(s != R_UnboundValue)
    return(this->vra->RToVTKTable(s));
  else
    return(0);

}

void vtkRInterface::AssignVTKTableToRVariable(vtkTable* table, const char* RVariableName)
{

  SEXP s;
  s = this->vra->VTKTableToR(table);
  defineVar(install(RVariableName), s, R_GlobalEnv);

}

int vtkRInterface::OutputBuffer(char* p, int n)
{

  this->buffer = p;
  this->buffer_size = n;
  if(this->buffer && (this->buffer_size > 0) )
    {
    this->buffer[0] = '\0';
    }
  return(1);

}

int vtkRInterface::FillOutputBuffer()
{

  FILE *fp;
  long len;

  if(this->buffer && (this->buffer_size > 0) )
    {
    fp = fopen(this->rs->GetROutputFilePath(),"rb");

    if(!fp)
      {
      vtkErrorMacro(<<"Can't open input file named " << this->rs->GetROutputFilePath());
      return(0);
      }

    fseek(fp,0,SEEK_END);
    len = ftell(fp);

    if(len == 0)
      {
      return(1);
      }

    if(len >= this->buffer_size)
      {
      fseek(fp,len-this->buffer_size+1,SEEK_SET);
      fread(this->buffer,1,this->buffer_size-1,fp);
      this->buffer[this->buffer_size-1] = '\0';
      }
    else
      {
      fseek(fp,0,SEEK_SET);
      fread(this->buffer,1,len,fp);
      this->buffer[len] = '\0';
      }

    fclose(fp);

    return(1);

    }
  else
    {
    return(0);
    }

}

void vtkRInterface::PrintSelf(ostream& os, vtkIndent indent)
{

  this->Superclass::PrintSelf(os, indent);

  os << indent << "buffer_size: " << this->buffer_size << endl;
  os << indent << "buffer: " << (this->buffer ? this->buffer : "NULL") << endl;

  if(this->vra)
    {
    this->vra->PrintSelf(os, indent);
    }

}

<|endoftext|>


<commit_before>#include <vector>
#include <iostream>
#include <random>

#include <SFML/Graphics.hpp>

#include "Universe.hpp"
#include "Body.hpp"

#define MASS 10
#define BASE_LINE 2
#define CLUSTER_RADIUS 300
#define CLUSTER_NUMBER 750
#define CLUSTER_MASS 1000

#ifdef _WIN32
	#define M_PI 3.14
#endif

using namespace sf;
using namespace std;

float gen_random_float();

int main()
{
	unsigned int width(800), height(600);
	RenderWindow window(VideoMode(width, height), "Gravity Simulation by Johan");
	View view(FloatRect(0, 0, width, height));

	// Drawable elements
	Universe universe;
	VertexArray line(Lines, 2);
	CircleShape base_line(BASE_LINE);

	// Logic vars
	Clock timer;
	float delta_t(0);
	int mass(MASS);
	Vector2f mousePosition;
	Vector2f start, end;
	bool running = true;
	bool is_placing = false;
	bool is_moving = false;
	bool trace = false;
	bool control = false;
	bool shift = false;

	// Some inits
	line[0].color = Color::Blue;
	line[1].color = Color::Green;
	base_line.setFillColor(Color::Blue);
	window.setView(view);

	while (running)
	{
		Event evt;
		while (window.pollEvent(evt))
		{
			if (evt.type == Event::Closed)
			{
				running = false;
			}

			if (evt.type == Event::Resized)
			{
				view.setSize(evt.size.width, evt.size.height);
				window.setView(view);
			}

			if (evt.type == Event::KeyPressed)
			{
				if (evt.key.code == Keyboard::Escape)
				{
					running = false;
				}

				switch (evt.key.code)
				{
				case Keyboard::PageUp:
				case Keyboard::Add:
					mass *= 10;
					if (mass < 0)
					{
						mass = MASS;
					}
					cout << "Mass is now " << mass << endl;
					break;

				case Keyboard::PageDown:
				case Keyboard::Subtract:
					if (mass > 10)
					{
						mass /= 10;
					}
					else
					{
						mass = MASS;
					}
					cout << "Mass is now " << mass << endl;
					break;

				case Keyboard::T:
					trace = !trace;
					cout << "Trace mode " << (trace ? "enabled" : "disabled") << endl;
					break;

				case Keyboard::Space:
					if (is_placing)
					{
						cout << "Planet placement cancelled" << endl;
					}

					is_placing = false;
					break;

				case Keyboard::LControl:
					control = true;
					break;

				case Keyboard::LShift:
					shift = true;
					break;

				case Keyboard::C:
					universe.createProtodisk(CLUSTER_NUMBER, CLUSTER_RADIUS, CLUSTER_MASS, view.getCenter());
					break;

				default:
					break;
				}
			}

			if (evt.type == Event::KeyReleased)
			{
				switch (evt.key.code)
				{
				case Keyboard::LControl:
					control = false;

				case Keyboard::LShift:
					shift = false;

				default:
					break;
				}
			}

			if (evt.type == Event::MouseButtonPressed)
			{
				if (shift)
				{
					universe.eraseAt(Vector2f(evt.mouseButton.x, evt.mouseButton.y));
				}
				else if (control)
				{
					is_moving = true;
				}
				else
				{
					is_placing = true;

					line[0].position = window.mapPixelToCoords(Vector2i(evt.mouseButton.x, evt.mouseButton.y));
					line[1].position = line[0].position;
					start = Vector2f(evt.mouseButton.x, evt.mouseButton.y);
					end = start;

					Vector2f base =
						window.mapPixelToCoords(Vector2i(evt.mouseButton.x - BASE_LINE, evt.mouseButton.y - BASE_LINE));
					base_line.setPosition(base);
				}
			}

			if (evt.type == Event::MouseMoved)
			{
				if (is_placing)
				{
					line[1].position = window.mapPixelToCoords(Vector2i(evt.mouseMove.x, evt.mouseMove.y));
					end = Vector2f(evt.mouseMove.x, evt.mouseMove.y);
				}

				if (is_moving)
				{
					view.move(mousePosition - Vector2f(evt.mouseMove.x, evt.mouseMove.y));
					window.setView(view);
				}

				mousePosition = Vector2f(evt.mouseMove.x, evt.mouseMove.y);
			}

			if (evt.type == Event::MouseButtonReleased)
			{
				if (is_placing)
				{
					is_placing = false;

					Vector2f direction = end - start;

					Body p(Vector2f(0, 0), mass, direction);

					p.position = Vector2f(line[0].position.x,
							line[0].position.y);;

					universe.addPlanet(p);
				}

				if (is_moving)
				{
					is_moving = false;
				}
			}

			if (evt.type == Event::MouseWheelMoved)
			{
				float factor = (evt.mouseWheel.delta < 1 ? 1.10 : 0.90);
				view.zoom(factor);
				window.setView(view);
			}
		}

		if (!trace)
		{
			window.clear();
		}

		// Delta T
		delta_t = timer.restart().asSeconds();

		// Vector Preview - wow - need an arrow - hard
		if (is_placing)
		{
			window.draw(line);
			window.draw(base_line);
		}

		// Planets
		universe.move(delta_t);
		universe.draw(window);

		window.display();

		sleep(milliseconds(3));
	}

	return 0;
}

float gen_random_float()
{
	static mt19937 engine(time(nullptr));
	static uniform_real_distribution<float> distribution(0.0f, 1.0f);

	static auto gen = std::bind(distribution, engine);

	return gen();
}<commit_msg>fixed view movement when zoom is changed<commit_after>#include <vector>
#include <iostream>
#include <random>

#include <SFML/Graphics.hpp>

#include "Universe.hpp"
#include "Body.hpp"

#define MASS 10
#define BASE_LINE 2
#define CLUSTER_RADIUS 300
#define CLUSTER_NUMBER 750
#define CLUSTER_MASS 1000

#ifdef _WIN32
	#define M_PI 3.14
#endif

using namespace sf;
using namespace std;

float gen_random_float();

int main()
{
	unsigned int width(800), height(600);
	RenderWindow window(VideoMode(width, height), "Gravity Simulation by Johan");
	View view(FloatRect(0, 0, width, height));

	// Drawable elements
	Universe universe;
	VertexArray line(Lines, 2);
	CircleShape base_line(BASE_LINE);

	// Logic vars
	Clock timer;
	float delta_t(0);
	int mass(MASS);
	Vector2f mousePosition;
	Vector2f start, end;
	bool running = true;
	bool is_placing = false;
	bool is_moving = false;
	bool trace = false;
	bool control = false;
	bool shift = false;

	// Some inits
	line[0].color = Color::Blue;
	line[1].color = Color::Green;
	base_line.setFillColor(Color::Blue);
	window.setView(view);

	while (running)
	{
		Event evt;
		while (window.pollEvent(evt))
		{
			if (evt.type == Event::Closed)
			{
				running = false;
			}

			if (evt.type == Event::Resized)
			{
				view.setSize(evt.size.width, evt.size.height);
				window.setView(view);
			}

			if (evt.type == Event::KeyPressed)
			{
				if (evt.key.code == Keyboard::Escape)
				{
					running = false;
				}

				switch (evt.key.code)
				{
				case Keyboard::PageUp:
				case Keyboard::Add:
					mass *= 10;
					if (mass < 0)
					{
						mass = MASS;
					}
					cout << "Mass is now " << mass << endl;
					break;

				case Keyboard::PageDown:
				case Keyboard::Subtract:
					if (mass > 10)
					{
						mass /= 10;
					}
					else
					{
						mass = MASS;
					}
					cout << "Mass is now " << mass << endl;
					break;

				case Keyboard::T:
					trace = !trace;
					cout << "Trace mode " << (trace ? "enabled" : "disabled") << endl;
					break;

				case Keyboard::Space:
					if (is_placing)
					{
						cout << "Planet placement cancelled" << endl;
					}

					is_placing = false;
					break;

				case Keyboard::LControl:
					control = true;
					break;

				case Keyboard::LShift:
					shift = true;
					break;

				case Keyboard::C:
					universe.createProtodisk(CLUSTER_NUMBER, CLUSTER_RADIUS, CLUSTER_MASS, view.getCenter());
					break;

				default:
					break;
				}
			}

			if (evt.type == Event::KeyReleased)
			{
				switch (evt.key.code)
				{
				case Keyboard::LControl:
					control = false;

				case Keyboard::LShift:
					shift = false;

				default:
					break;
				}
			}

			if (evt.type == Event::MouseButtonPressed)
			{
				if (shift)
				{
					universe.eraseAt(Vector2f(evt.mouseButton.x, evt.mouseButton.y));
				}
				else if (control)
				{
					is_moving = true;
				}
				else
				{
					is_placing = true;

					line[0].position = window.mapPixelToCoords(Vector2i(evt.mouseButton.x, evt.mouseButton.y));
					line[1].position = line[0].position;
					start = Vector2f(evt.mouseButton.x, evt.mouseButton.y);
					end = start;

					Vector2f base =
						window.mapPixelToCoords(Vector2i(evt.mouseButton.x - BASE_LINE, evt.mouseButton.y - BASE_LINE));
					base_line.setPosition(base);
				}
			}

			if (evt.type == Event::MouseMoved)
			{
				if (is_placing)
				{
					line[1].position = window.mapPixelToCoords(Vector2i(evt.mouseMove.x, evt.mouseMove.y));
					end = Vector2f(evt.mouseMove.x, evt.mouseMove.y);
				}

				if (is_moving)
				{
					view.move(mousePosition - window.mapPixelToCoords(Vector2i(evt.mouseMove.x, evt.mouseMove.y)));
					window.setView(view);
				}

				mousePosition = window.mapPixelToCoords(Vector2i(evt.mouseMove.x, evt.mouseMove.y));
			}

			if (evt.type == Event::MouseButtonReleased)
			{
				if (is_placing)
				{
					is_placing = false;

					Vector2f direction = end - start;

					Body p(Vector2f(0, 0), mass, direction);

					p.position = Vector2f(line[0].position.x,
							line[0].position.y);;

					universe.addPlanet(p);
				}

				if (is_moving)
				{
					is_moving = false;
				}
			}

			if (evt.type == Event::MouseWheelMoved)
			{
				float factor = (evt.mouseWheel.delta < 1 ? 1.10 : 0.90);
				view.zoom(factor);
				window.setView(view);
			}
		}

		if (!trace)
		{
			window.clear();
		}

		// Delta T
		delta_t = timer.restart().asSeconds();

		// Vector Preview - wow - need an arrow - hard
		if (is_placing)
		{
			window.draw(line);
			window.draw(base_line);
		}

		// Planets
		universe.move(delta_t);
		universe.draw(window);

		window.display();

		sleep(milliseconds(3));
	}

	return 0;
}

float gen_random_float()
{
	static mt19937 engine(time(nullptr));
	static uniform_real_distribution<float> distribution(0.0f, 1.0f);

	static auto gen = std::bind(distribution, engine);

	return gen();
}<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include <ROOT/RError.hxx>

#include <stdexcept>

using RException = ROOT::Experimental::RException;

namespace {

static ROOT::Experimental::RResult<void> TestFailure()
{
   R__FAIL("test failure");
}

static ROOT::Experimental::RResult<void> TestSuccess()
{
   R__SUCCESS
}

static ROOT::Experimental::RResult<int> TestSyscall(bool succeed)
{
   if (succeed)
      return 42;
   R__FAIL("failure");
}

static ROOT::Experimental::RResult<int> TestChain(bool succeed)
{
   auto rv = TestSyscall(succeed);
   R__FORWARD_RESULT(rv);
}

class ExceptionX : public std::runtime_error {
public:
   explicit ExceptionX(const std::string &what) : std::runtime_error(what) {}
};

} // anonymous namespace

TEST(Exception, Report)
{
   bool exceptionThrown = false;
   try {
      TestChain(false);
   } catch (const RException& e) {
      exceptionThrown = true;
      ASSERT_EQ(2U, e.GetError().GetStackTrace().size());
      EXPECT_THAT(e.GetError().GetStackTrace().at(0).fFunction, ::testing::HasSubstr("TestSyscall(bool)"));
      EXPECT_THAT(e.GetError().GetStackTrace().at(1).fFunction, ::testing::HasSubstr("TestChain(bool)"));
   }
   EXPECT_TRUE(exceptionThrown);
}

TEST(Exception, DiscardReturnValue)
{
   EXPECT_THROW(TestFailure(), RException);
   EXPECT_NO_THROW(TestSuccess());
}

TEST(Exception, CheckReturnValue)
{
   auto rv = TestFailure();
   EXPECT_FALSE(rv);
   // No exception / crash when the scope closes
}

TEST(Exception, DoubleThrow)
{
   try {
      auto rv = TestFailure();
      // Throwing ExceptionX will destruct rv along the way. Since rv carries an error state, it would normally
      // throw an exception itself. In this test, we verify that rv surpresses throwing an exception if another
      // exception is currently active.
      throw ExceptionX("something else went wrong");
   } catch (const ExceptionX&) {
      // This will only catch ExceptionX but not RException. In case rv mistakenly throws an exception,
      // we would notice the test failure by a crash of the unit test.
   }
}

TEST(Exception, Syscall)
{
   auto fd = TestSyscall(true);
   if (!fd) {
      // In production code, we would expect error handling code other than throw
      EXPECT_THROW(fd.Throw(), RException);
   }
   EXPECT_EQ(42, fd.Get());

   EXPECT_THROW(TestSyscall(false).Get(), RException);
}
<commit_msg>[v7, exceptions] minor improvement to unit test<commit_after>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include <ROOT/RError.hxx>

#include <stdexcept>

using RException = ROOT::Experimental::RException;

namespace {

static ROOT::Experimental::RResult<void> TestFailure()
{
   R__FAIL("test failure");
}

static ROOT::Experimental::RResult<void> TestSuccess()
{
   return ROOT::Experimental::RResult<void>::Success();
}

static ROOT::Experimental::RResult<int> TestSyscall(bool succeed)
{
   if (succeed)
      return 42;
   R__FAIL("failure");
}

static ROOT::Experimental::RResult<int> TestChain(bool succeed)
{
   auto rv = TestSyscall(succeed);
   R__FORWARD_RESULT(rv);
}

class ExceptionX : public std::runtime_error {
public:
   explicit ExceptionX(const std::string &what) : std::runtime_error(what) {}
};

} // anonymous namespace

TEST(Exception, Report)
{
   try {
      TestChain(false);
      EXPECT_EQ("Above line should have thrown!", nullptr);
   } catch (const RException& e) {
      ASSERT_EQ(2U, e.GetError().GetStackTrace().size());
      EXPECT_THAT(e.GetError().GetStackTrace().at(0).fFunction, ::testing::HasSubstr("TestSyscall(bool)"));
      EXPECT_THAT(e.GetError().GetStackTrace().at(1).fFunction, ::testing::HasSubstr("TestChain(bool)"));
   }
}

TEST(Exception, DiscardReturnValue)
{
   EXPECT_THROW(TestFailure(), RException);
   EXPECT_NO_THROW(TestSuccess());
}

TEST(Exception, CheckReturnValue)
{
   auto rv = TestFailure();
   EXPECT_FALSE(rv);
   // No exception / crash when the scope closes
}

TEST(Exception, DoubleThrow)
{
   try {
      auto rv = TestFailure();
      // Throwing ExceptionX will destruct rv along the way. Since rv carries an error state, it would normally
      // throw an exception itself. In this test, we verify that rv surpresses throwing an exception if another
      // exception is currently active.
      throw ExceptionX("something else went wrong");
   } catch (const ExceptionX&) {
      // This will only catch ExceptionX but not RException. In case rv mistakenly throws an exception,
      // we would notice the test failure by a crash of the unit test.
   }
}

TEST(Exception, Syscall)
{
   auto fd = TestSyscall(true);
   if (!fd) {
      // In production code, we would expect error handling code other than throw
      EXPECT_THROW(fd.Throw(), RException);
   }
   EXPECT_EQ(42, fd.Get());

   EXPECT_THROW(TestSyscall(false).Get(), RException);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "modules/accessibility/AXTableCell.h"

#include "core/rendering/RenderTableCell.h"
#include "modules/accessibility/AXObjectCacheImpl.h"

namespace blink {

using namespace HTMLNames;

AXTableCell::AXTableCell(RenderObject* renderer, AXObjectCacheImpl* axObjectCache)
    : AXRenderObject(renderer, axObjectCache)
{
}

AXTableCell::~AXTableCell()
{
}

PassRefPtr<AXTableCell> AXTableCell::create(RenderObject* renderer, AXObjectCacheImpl* axObjectCache)
{
    return adoptRef(new AXTableCell(renderer, axObjectCache));
}

bool AXTableCell::isTableHeaderCell() const
{
    return node() && node()->hasTagName(thTag);
}

bool AXTableCell::computeAccessibilityIsIgnored() const
{
    AXObjectInclusion decision = defaultObjectInclusion();
    if (decision == IncludeObject)
        return false;
    if (decision == IgnoreObject)
        return true;

    if (!isTableCell())
        return AXRenderObject::computeAccessibilityIsIgnored();

    return false;
}

AXObject* AXTableCell::parentTable() const
{
    if (!m_renderer || !m_renderer->isTableCell())
        return 0;

    // If the document no longer exists, we might not have an axObjectCache.
    if (!axObjectCache())
        return 0;

    // Do not use getOrCreate. parentTable() can be called while the render tree is being modified
    // by javascript, and creating a table element may try to access the render tree while in a bad state.
    // By using only get() implies that the AXTable must be created before AXTableCells. This should
    // always be the case when AT clients access a table.
    // https://bugs.webkit.org/show_bug.cgi?id=42652
    return axObjectCache()->get(toRenderTableCell(m_renderer)->table());
}

bool AXTableCell::isTableCell() const
{
    AXObject* parent = parentObjectUnignored();
    if (!parent || !parent->isTableRow())
        return false;

    return true;
}

static AccessibilityRole decideRoleFromSibling(Node* siblingNode)
{
    if (!siblingNode)
        return CellRole;
    if (siblingNode->hasTagName(thTag))
        return ColumnHeaderRole;
    if (siblingNode->hasTagName(tdTag))
        return RowHeaderRole;
    return CellRole;
}

AccessibilityRole AXTableCell::scanToDecideHeaderRole()
{
    if (!isTableHeaderCell())
        return CellRole;

    // Check scope attribute first.
    const AtomicString& scope = getAttribute(scopeAttr);
    if (equalIgnoringCase(scope, "row"))
        return RowHeaderRole;
    if (equalIgnoringCase(scope, "col"))
        return ColumnHeaderRole;

    // Check the previous cell and the next cell
    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    AccessibilityRole headerRole = CellRole;

    // if header is preceded by header cells then it's a column header,
    // if it is preceded by cells then it's a row header.
    if (RenderTableCell* cell = renderCell->previousCell()) {
        Node* siblingNode = cell->node();
        headerRole = decideRoleFromSibling(siblingNode);
        if (headerRole != CellRole)
            return headerRole;
    }
    // if header is followed by header cells then it's a column header,
    // if it is followed by cells then it's a row header.
    if (RenderTableCell* cell = renderCell->nextCell()) {
        Node* siblingNode = cell->node();
        headerRole = decideRoleFromSibling(siblingNode);
    }
    return headerRole;
}

AccessibilityRole AXTableCell::determineAccessibilityRole()
{
    if (!isTableCell())
        return AXRenderObject::determineAccessibilityRole();

    return scanToDecideHeaderRole();
}

void AXTableCell::rowIndexRange(pair<unsigned, unsigned>& rowRange)
{
    if (!m_renderer || !m_renderer->isTableCell())
        return;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    rowRange.first = renderCell->rowIndex();
    rowRange.second = renderCell->rowSpan();

    // since our table might have multiple sections, we have to offset our row appropriately
    RenderTableSection* section = renderCell->section();
    RenderTable* table = renderCell->table();
    if (!table || !section)
        return;

    RenderTableSection* tableSection = table->topSection();
    unsigned rowOffset = 0;
    while (tableSection) {
        if (tableSection == section)
            break;
        rowOffset += tableSection->numRows();
        tableSection = table->sectionBelow(tableSection, SkipEmptySections);
    }

    rowRange.first += rowOffset;
}

void AXTableCell::columnIndexRange(pair<unsigned, unsigned>& columnRange)
{
    if (!m_renderer || !m_renderer->isTableCell())
        return;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    columnRange.first = renderCell->col();
    columnRange.second = renderCell->colSpan();
}

AXObject* AXTableCell::titleUIElement() const
{
    // Try to find if the first cell in this row is a <th>. If it is,
    // then it can act as the title ui element. (This is only in the
    // case when the table is not appearing as an AXTable.)
    if (isTableCell() || !m_renderer || !m_renderer->isTableCell())
        return 0;

    // Table cells that are th cannot have title ui elements, since by definition
    // they are title ui elements
    Node* node = m_renderer->node();
    if (node && node->hasTagName(thTag))
        return 0;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);

    // If this cell is in the first column, there is no need to continue.
    int col = renderCell->col();
    if (!col)
        return 0;

    int row = renderCell->rowIndex();

    RenderTableSection* section = renderCell->section();
    if (!section)
        return 0;

    RenderTableCell* headerCell = section->primaryCellAt(row, 0);
    if (!headerCell || headerCell == renderCell)
        return 0;

    Node* cellElement = headerCell->node();
    if (!cellElement || !cellElement->hasTagName(thTag))
        return 0;

    return axObjectCache()->getOrCreate(headerCell);
}

} // namespace blink
<commit_msg>Use isTableHeaderCell() where appropriate.<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "modules/accessibility/AXTableCell.h"

#include "core/rendering/RenderTableCell.h"
#include "modules/accessibility/AXObjectCacheImpl.h"

namespace blink {

using namespace HTMLNames;

AXTableCell::AXTableCell(RenderObject* renderer, AXObjectCacheImpl* axObjectCache)
    : AXRenderObject(renderer, axObjectCache)
{
}

AXTableCell::~AXTableCell()
{
}

PassRefPtr<AXTableCell> AXTableCell::create(RenderObject* renderer, AXObjectCacheImpl* axObjectCache)
{
    return adoptRef(new AXTableCell(renderer, axObjectCache));
}

bool AXTableCell::isTableHeaderCell() const
{
    return node() && node()->hasTagName(thTag);
}

bool AXTableCell::computeAccessibilityIsIgnored() const
{
    AXObjectInclusion decision = defaultObjectInclusion();
    if (decision == IncludeObject)
        return false;
    if (decision == IgnoreObject)
        return true;

    if (!isTableCell())
        return AXRenderObject::computeAccessibilityIsIgnored();

    return false;
}

AXObject* AXTableCell::parentTable() const
{
    if (!m_renderer || !m_renderer->isTableCell())
        return 0;

    // If the document no longer exists, we might not have an axObjectCache.
    if (!axObjectCache())
        return 0;

    // Do not use getOrCreate. parentTable() can be called while the render tree is being modified
    // by javascript, and creating a table element may try to access the render tree while in a bad state.
    // By using only get() implies that the AXTable must be created before AXTableCells. This should
    // always be the case when AT clients access a table.
    // https://bugs.webkit.org/show_bug.cgi?id=42652
    return axObjectCache()->get(toRenderTableCell(m_renderer)->table());
}

bool AXTableCell::isTableCell() const
{
    AXObject* parent = parentObjectUnignored();
    if (!parent || !parent->isTableRow())
        return false;

    return true;
}

static AccessibilityRole decideRoleFromSibling(Node* siblingNode)
{
    if (!siblingNode)
        return CellRole;
    if (siblingNode->hasTagName(thTag))
        return ColumnHeaderRole;
    if (siblingNode->hasTagName(tdTag))
        return RowHeaderRole;
    return CellRole;
}

AccessibilityRole AXTableCell::scanToDecideHeaderRole()
{
    if (!isTableHeaderCell())
        return CellRole;

    // Check scope attribute first.
    const AtomicString& scope = getAttribute(scopeAttr);
    if (equalIgnoringCase(scope, "row"))
        return RowHeaderRole;
    if (equalIgnoringCase(scope, "col"))
        return ColumnHeaderRole;

    // Check the previous cell and the next cell
    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    AccessibilityRole headerRole = CellRole;

    // if header is preceded by header cells then it's a column header,
    // if it is preceded by cells then it's a row header.
    if (RenderTableCell* cell = renderCell->previousCell()) {
        Node* siblingNode = cell->node();
        headerRole = decideRoleFromSibling(siblingNode);
        if (headerRole != CellRole)
            return headerRole;
    }
    // if header is followed by header cells then it's a column header,
    // if it is followed by cells then it's a row header.
    if (RenderTableCell* cell = renderCell->nextCell()) {
        Node* siblingNode = cell->node();
        headerRole = decideRoleFromSibling(siblingNode);
    }
    return headerRole;
}

AccessibilityRole AXTableCell::determineAccessibilityRole()
{
    if (!isTableCell())
        return AXRenderObject::determineAccessibilityRole();

    return scanToDecideHeaderRole();
}

void AXTableCell::rowIndexRange(pair<unsigned, unsigned>& rowRange)
{
    if (!m_renderer || !m_renderer->isTableCell())
        return;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    rowRange.first = renderCell->rowIndex();
    rowRange.second = renderCell->rowSpan();

    // since our table might have multiple sections, we have to offset our row appropriately
    RenderTableSection* section = renderCell->section();
    RenderTable* table = renderCell->table();
    if (!table || !section)
        return;

    RenderTableSection* tableSection = table->topSection();
    unsigned rowOffset = 0;
    while (tableSection) {
        if (tableSection == section)
            break;
        rowOffset += tableSection->numRows();
        tableSection = table->sectionBelow(tableSection, SkipEmptySections);
    }

    rowRange.first += rowOffset;
}

void AXTableCell::columnIndexRange(pair<unsigned, unsigned>& columnRange)
{
    if (!m_renderer || !m_renderer->isTableCell())
        return;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);
    columnRange.first = renderCell->col();
    columnRange.second = renderCell->colSpan();
}

AXObject* AXTableCell::titleUIElement() const
{
    // Try to find if the first cell in this row is a <th>. If it is,
    // then it can act as the title ui element. (This is only in the
    // case when the table is not appearing as an AXTable.)
    if (isTableCell() || !m_renderer || !m_renderer->isTableCell())
        return 0;

    // Table cells that are th cannot have title ui elements, since by definition
    // they are title ui elements
    if (isTableHeaderCell())
        return 0;

    RenderTableCell* renderCell = toRenderTableCell(m_renderer);

    // If this cell is in the first column, there is no need to continue.
    int col = renderCell->col();
    if (!col)
        return 0;

    int row = renderCell->rowIndex();

    RenderTableSection* section = renderCell->section();
    if (!section)
        return 0;

    RenderTableCell* headerCell = section->primaryCellAt(row, 0);
    if (!headerCell || headerCell == renderCell)
        return 0;

    Node* cellElement = headerCell->node();
    if (!cellElement || !cellElement->hasTagName(thTag))
        return 0;

    return axObjectCache()->getOrCreate(headerCell);
}

} // namespace blink
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#if !OS(WIN) && !OS(ANDROID)
#include "SkFontConfigInterface.h"
#endif
#include "SkFontMgr.h"
#include "SkStream.h"
#include "SkTypeface.h"
#include "platform/NotImplemented.h"
#include "platform/fonts/AlternateFontFamily.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "public/platform/linux/WebSandboxSupport.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/CString.h"
#include <unicode/locid.h>

#if !OS(WIN) && !OS(ANDROID)
static SkStream* streamForFontconfigInterfaceId(int fontconfigInterfaceId)
{
    SkAutoTUnref<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
    SkFontConfigInterface::FontIdentity fontIdentity;
    fontIdentity.fID = fontconfigInterfaceId;
    return fci->openStream(fontIdentity);
}
#endif

namespace blink {

void FontCache::platformInit()
{
}

PassRefPtr<SimpleFontData> FontCache::fallbackOnStandardFontStyle(
    const FontDescription& fontDescription, UChar32 character)
{
    FontDescription substituteDescription(fontDescription);
    substituteDescription.setStyle(FontStyleNormal);
    substituteDescription.setWeight(FontWeightNormal);

    FontFaceCreationParams creationParams(substituteDescription.family().family());
    FontPlatformData* substitutePlatformData = getFontPlatformData(substituteDescription, creationParams);
    if (substitutePlatformData && substitutePlatformData->fontContainsCharacter(character)) {
        FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
        platformData.setSyntheticBold(fontDescription.weight() >= FontWeight600);
        platformData.setSyntheticItalic(fontDescription.style() == FontStyleItalic);
        return fontDataFromFontPlatformData(&platformData, DoNotRetain);
    }

    return nullptr;
}

#if !OS(WIN) && !OS(ANDROID)
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
{
    // First try the specified font with standard style & weight.
    if (fontDescription.style() == FontStyleItalic
        || fontDescription.weight() >= FontWeight600) {
        RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
            fontDescription, c);
        if (fontData)
            return fontData;
    }

    FontCache::PlatformFallbackFont fallbackFont;
    FontCache::getFontForCharacter(c, "", &fallbackFont);
    if (fallbackFont.name.isEmpty())
        return nullptr;

    FontFaceCreationParams creationParams;
    creationParams = FontFaceCreationParams(fallbackFont.filename, fallbackFont.fontconfigInterfaceId, fallbackFont.ttcIndex);

    // Changes weight and/or italic of given FontDescription depends on
    // the result of fontconfig so that keeping the correct font mapping
    // of the given character. See http://crbug.com/32109 for details.
    bool shouldSetSyntheticBold = false;
    bool shouldSetSyntheticItalic = false;
    FontDescription description(fontDescription);
    if (fallbackFont.isBold && description.weight() < FontWeightBold)
        description.setWeight(FontWeightBold);
    if (!fallbackFont.isBold && description.weight() >= FontWeightBold) {
        shouldSetSyntheticBold = true;
        description.setWeight(FontWeightNormal);
    }
    if (fallbackFont.isItalic && description.style() == FontStyleNormal)
        description.setStyle(FontStyleItalic);
    if (!fallbackFont.isItalic && description.style() == FontStyleItalic) {
        shouldSetSyntheticItalic = true;
        description.setStyle(FontStyleNormal);
    }

    FontPlatformData* substitutePlatformData = getFontPlatformData(description, creationParams);
    if (!substitutePlatformData)
        return nullptr;
    FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
    platformData.setSyntheticBold(shouldSetSyntheticBold);
    platformData.setSyntheticItalic(shouldSetSyntheticItalic);
    return fontDataFromFontPlatformData(&platformData, DoNotRetain);
}

#endif // !OS(WIN) && !OS(ANDROID)

PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain)
{
    const FontFaceCreationParams fallbackCreationParams(getFallbackFontFamily(description));
    const FontPlatformData* fontPlatformData = getFontPlatformData(description, fallbackCreationParams);

    // We should at least have Sans or Arial which is the last resort fallback of SkFontHost ports.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, sansCreationParams, (AtomicString("Sans", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, sansCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, arialCreationParams, (AtomicString("Arial", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, arialCreationParams);
    }
#if OS(WIN)
    // Try some more Windows-specific fallbacks.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, msuigothicCreationParams, (AtomicString("MS UI Gothic", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, msuigothicCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, mssansserifCreationParams, (AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, mssansserifCreationParams);
    }
#endif

    ASSERT(fontPlatformData);
    return fontDataFromFontPlatformData(fontPlatformData, shouldRetain);
}

PassRefPtr<SkTypeface> FontCache::createTypeface(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, CString& name)
{
#if !OS(WIN) && !OS(ANDROID)
    if (creationParams.creationType() == CreateFontByFciIdAndTtcIndex) {
        // TODO(dro): crbug.com/381620 Use creationParams.ttcIndex() after
        // https://code.google.com/p/skia/issues/detail?id=1186 gets fixed.
        SkTypeface* typeface = nullptr;
        if (blink::Platform::current()->sandboxSupport())
            typeface = SkTypeface::CreateFromStream(streamForFontconfigInterfaceId(creationParams.fontconfigInterfaceId()));
        else
            typeface = SkTypeface::CreateFromFile(creationParams.filename().data());

        if (typeface)
            return adoptRef(typeface);
    }
#endif

    AtomicString family = creationParams.family();
    // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
    // the fallback name (like "monospace") that fontconfig understands.
    if (!family.length() || family.startsWith("-webkit-")) {
        name = getFallbackFontFamily(fontDescription).string().utf8();
    } else {
        // convert the name to utf8
        name = family.utf8();
    }

    int style = SkTypeface::kNormal;
    if (fontDescription.weight() >= FontWeight600)
        style |= SkTypeface::kBold;
    if (fontDescription.style())
        style |= SkTypeface::kItalic;

#if OS(WIN)
    if (s_sideloadedFonts) {
        HashMap<String, SkTypeface*>::iterator sideloadedFont = s_sideloadedFonts->find(name.data());
        if (sideloadedFont != s_sideloadedFonts->end()) {
            return adoptRef(sideloadedFont->value);
        }
    }
    // FIXME: Use SkFontStyle and matchFamilyStyle instead of legacyCreateTypeface.
    if (m_fontManager)
        return adoptRef(m_fontManager->legacyCreateTypeface(name.data(), style));
#endif

    return adoptRef(SkTypeface::CreateFromName(name.data(), static_cast<SkTypeface::Style>(style)));
}

#if !OS(WIN)
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
{
    CString name;
    RefPtr<SkTypeface> tf(createTypeface(fontDescription, creationParams, name));
    if (!tf)
        return 0;

    FontPlatformData* result = new FontPlatformData(tf,
        name.data(),
        fontSize,
        (fontDescription.weight() >= FontWeight600 && !tf->isBold()) || fontDescription.isSyntheticBold(),
        (fontDescription.style() && !tf->isItalic()) || fontDescription.isSyntheticItalic(),
        fontDescription.orientation(),
        fontDescription.useSubpixelPositioning());
    return result;
}
#endif // !OS(WIN)

} // namespace blink
<commit_msg>Fix font instantiation assertion failure on session restore<commit_after>/*
 * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#if !OS(WIN) && !OS(ANDROID)
#include "SkFontConfigInterface.h"
#endif
#include "SkFontMgr.h"
#include "SkStream.h"
#include "SkTypeface.h"
#include "platform/NotImplemented.h"
#include "platform/fonts/AlternateFontFamily.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
#include "platform/fonts/SimpleFontData.h"
#include "public/platform/Platform.h"
#include "public/platform/linux/WebSandboxSupport.h"
#include "wtf/Assertions.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/CString.h"
#include <unicode/locid.h>

#if !OS(WIN) && !OS(ANDROID)
static SkStream* streamForFontconfigInterfaceId(int fontconfigInterfaceId)
{
    SkAutoTUnref<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal());
    SkFontConfigInterface::FontIdentity fontIdentity;
    fontIdentity.fID = fontconfigInterfaceId;
    return fci->openStream(fontIdentity);
}
#endif

namespace blink {

void FontCache::platformInit()
{
}

PassRefPtr<SimpleFontData> FontCache::fallbackOnStandardFontStyle(
    const FontDescription& fontDescription, UChar32 character)
{
    FontDescription substituteDescription(fontDescription);
    substituteDescription.setStyle(FontStyleNormal);
    substituteDescription.setWeight(FontWeightNormal);

    FontFaceCreationParams creationParams(substituteDescription.family().family());
    FontPlatformData* substitutePlatformData = getFontPlatformData(substituteDescription, creationParams);
    if (substitutePlatformData && substitutePlatformData->fontContainsCharacter(character)) {
        FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
        platformData.setSyntheticBold(fontDescription.weight() >= FontWeight600);
        platformData.setSyntheticItalic(fontDescription.style() == FontStyleItalic);
        return fontDataFromFontPlatformData(&platformData, DoNotRetain);
    }

    return nullptr;
}

#if !OS(WIN) && !OS(ANDROID)
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
{
    // First try the specified font with standard style & weight.
    if (fontDescription.style() == FontStyleItalic
        || fontDescription.weight() >= FontWeight600) {
        RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
            fontDescription, c);
        if (fontData)
            return fontData;
    }

    FontCache::PlatformFallbackFont fallbackFont;
    FontCache::getFontForCharacter(c, "", &fallbackFont);
    if (fallbackFont.name.isEmpty())
        return nullptr;

    FontFaceCreationParams creationParams;
    creationParams = FontFaceCreationParams(fallbackFont.filename, fallbackFont.fontconfigInterfaceId, fallbackFont.ttcIndex);

    // Changes weight and/or italic of given FontDescription depends on
    // the result of fontconfig so that keeping the correct font mapping
    // of the given character. See http://crbug.com/32109 for details.
    bool shouldSetSyntheticBold = false;
    bool shouldSetSyntheticItalic = false;
    FontDescription description(fontDescription);
    if (fallbackFont.isBold && description.weight() < FontWeightBold)
        description.setWeight(FontWeightBold);
    if (!fallbackFont.isBold && description.weight() >= FontWeightBold) {
        shouldSetSyntheticBold = true;
        description.setWeight(FontWeightNormal);
    }
    if (fallbackFont.isItalic && description.style() == FontStyleNormal)
        description.setStyle(FontStyleItalic);
    if (!fallbackFont.isItalic && description.style() == FontStyleItalic) {
        shouldSetSyntheticItalic = true;
        description.setStyle(FontStyleNormal);
    }

    FontPlatformData* substitutePlatformData = getFontPlatformData(description, creationParams);
    if (!substitutePlatformData)
        return nullptr;
    FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
    platformData.setSyntheticBold(shouldSetSyntheticBold);
    platformData.setSyntheticItalic(shouldSetSyntheticItalic);
    return fontDataFromFontPlatformData(&platformData, DoNotRetain);
}

#endif // !OS(WIN) && !OS(ANDROID)

PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain)
{
    const FontFaceCreationParams fallbackCreationParams(getFallbackFontFamily(description));
    const FontPlatformData* fontPlatformData = getFontPlatformData(description, fallbackCreationParams);

    // We should at least have Sans or Arial which is the last resort fallback of SkFontHost ports.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, sansCreationParams, (AtomicString("Sans", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, sansCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, arialCreationParams, (AtomicString("Arial", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, arialCreationParams);
    }
#if OS(WIN)
    // Try some more Windows-specific fallbacks.
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, msuigothicCreationParams, (AtomicString("MS UI Gothic", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, msuigothicCreationParams);
    }
    if (!fontPlatformData) {
        DEFINE_STATIC_LOCAL(const FontFaceCreationParams, mssansserifCreationParams, (AtomicString("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)));
        fontPlatformData = getFontPlatformData(description, mssansserifCreationParams);
    }
#endif

    ASSERT(fontPlatformData);
    return fontDataFromFontPlatformData(fontPlatformData, shouldRetain);
}

PassRefPtr<SkTypeface> FontCache::createTypeface(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, CString& name)
{
#if !OS(WIN) && !OS(ANDROID)
    if (creationParams.creationType() == CreateFontByFciIdAndTtcIndex) {
        // TODO(dro): crbug.com/381620 Use creationParams.ttcIndex() after
        // https://code.google.com/p/skia/issues/detail?id=1186 gets fixed.
        SkTypeface* typeface = nullptr;
        if (blink::Platform::current()->sandboxSupport())
            typeface = SkTypeface::CreateFromStream(streamForFontconfigInterfaceId(creationParams.fontconfigInterfaceId()));
        else
            typeface = SkTypeface::CreateFromFile(creationParams.filename().data());

        if (typeface)
            return adoptRef(typeface);
        else
            return nullptr;
    }
#endif

    AtomicString family = creationParams.family();
    // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into
    // the fallback name (like "monospace") that fontconfig understands.
    if (!family.length() || family.startsWith("-webkit-")) {
        name = getFallbackFontFamily(fontDescription).string().utf8();
    } else {
        // convert the name to utf8
        name = family.utf8();
    }

    int style = SkTypeface::kNormal;
    if (fontDescription.weight() >= FontWeight600)
        style |= SkTypeface::kBold;
    if (fontDescription.style())
        style |= SkTypeface::kItalic;

#if OS(WIN)
    if (s_sideloadedFonts) {
        HashMap<String, SkTypeface*>::iterator sideloadedFont = s_sideloadedFonts->find(name.data());
        if (sideloadedFont != s_sideloadedFonts->end()) {
            return adoptRef(sideloadedFont->value);
        }
    }
    // FIXME: Use SkFontStyle and matchFamilyStyle instead of legacyCreateTypeface.
    if (m_fontManager)
        return adoptRef(m_fontManager->legacyCreateTypeface(name.data(), style));
#endif

    return adoptRef(SkTypeface::CreateFromName(name.data(), static_cast<SkTypeface::Style>(style)));
}

#if !OS(WIN)
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
{
    CString name;
    RefPtr<SkTypeface> tf(createTypeface(fontDescription, creationParams, name));
    if (!tf)
        return 0;

    FontPlatformData* result = new FontPlatformData(tf,
        name.data(),
        fontSize,
        (fontDescription.weight() >= FontWeight600 && !tf->isBold()) || fontDescription.isSyntheticBold(),
        (fontDescription.style() && !tf->isItalic()) || fontDescription.isSyntheticItalic(),
        fontDescription.orientation(),
        fontDescription.useSubpixelPositioning());
    return result;
}
#endif // !OS(WIN)

} // namespace blink
<|endoftext|>


<commit_before>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Conditions/SelfCondition.hpp>
#include <Rosetta/Games/Game.hpp>
#include <utility>

namespace RosettaStone
{
SelfCondition::SelfCondition(std::function<bool(Entity*)> func)
    : m_func(std::move(func))
{
    // Do nothing
}

SelfCondition SelfCondition::IsControllingRace(Race race)
{
    return SelfCondition([&](Entity* entity) -> bool {
        for (auto& minion : entity->GetOwner().GetField().GetAllMinions())
        {
            if (minion->card.race == race)
            {
                return true;
            }
        }

        return false;
    });
}

bool SelfCondition::Evaluate(Entity* entity) const
{
    return m_func(entity);
}
}  // namespace RosettaStone
<commit_msg>fix: Correct invalid capture (reference -> value)<commit_after>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Conditions/SelfCondition.hpp>
#include <Rosetta/Games/Game.hpp>
#include <utility>

namespace RosettaStone
{
SelfCondition::SelfCondition(std::function<bool(Entity*)> func)
    : m_func(std::move(func))
{
    // Do nothing
}

SelfCondition SelfCondition::IsControllingRace(Race race)
{
    return SelfCondition([=](Entity* entity) -> bool {
        for (auto& minion : entity->GetOwner().GetField().GetAllMinions())
        {
            if (minion->card.race == race)
            {
                return true;
            }
        }

        return false;
    });
}

bool SelfCondition::Evaluate(Entity* entity) const
{
    return m_func(entity);
}
}  // namespace RosettaStone
<|endoftext|>