# Copyright 2016 The PDFium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/config/clang/clang.gni")
import("//build/config/gclient_args.gni")
import("//testing/test.gni")
import("pdfium.gni")

group("default") {
  testonly = true
  deps = [ ":pdfium" ]
  if (pdf_is_standalone) {
    deps += [ ":pdfium_all" ]
  }
}

group("freetype_common") {
  public_deps = []
  if (pdf_bundle_freetype) {
    public_deps += [ "third_party:fx_freetype" ]
  } else {
    public_deps += [ "//build/config/freetype" ]
  }
}

config("pdfium_common_config") {
  cflags = []
  cflags_cc = []
  ldflags = []
  include_dirs = [ "." ]
  defines = []

  if (!use_system_libopenjpeg2) {
    defines += [ "OPJ_STATIC" ]
  }

  if (pdf_enable_click_logging) {
    defines += [ "PDF_ENABLE_CLICK_LOGGING" ]
  }

  if (pdf_use_skia && pdf_enable_fontations) {
    defines += [ "PDF_ENABLE_FONTATIONS" ]
  }

  if (pdf_use_partition_alloc) {
    defines += [ "PDF_USE_PARTITION_ALLOC" ]
  }

  if (is_win) {
    # Assume UTF-8 by default to avoid code page dependencies.
    cflags += [ "/utf-8" ]

    if (!is_clang) {
      cflags += [
        # Warnings permanently disabled:

        # C4091: 'typedef ': ignored on left of 'X' when no variable is
        #                    declared.
        # This happens in a number of Windows headers. Dumb.
        "/wd4091",

        # C4127: conditional expression is constant
        # This warning can in theory catch dead code and other problems, but
        # triggers in far too many desirable cases where the conditional
        # expression is either set by macros or corresponds some legitimate
        # compile-time constant expression (due to constant template args,
        # conditionals comparing the sizes of different types, etc.).  Some of
        # these can be worked around, but it's not worth it.
        "/wd4127",

        # C4251: 'identifier' : class 'type' needs to have dll-interface to be
        #        used by clients of class 'type2'
        # This is necessary for the shared library build.
        "/wd4251",

        # C4275:  non dll-interface class used as base for dll-interface class
        # This points out a potential (but rare) problem with referencing static
        # fields of a non-exported base, through the base's non-exported inline
        # functions, or directly. The warning is subtle enough that people just
        # suppressed it when they saw it, so it's not worth it.
        "/wd4275",

        # C4312 is a VS 2015 64-bit warning for integer to larger pointer.
        # TODO(brucedawson): fix warnings, crbug.com/554200
        "/wd4312",

        # C4324 warns when padding is added to fulfill alignas requirements,
        # but can trigger in benign cases that are difficult to individually
        # suppress.
        "/wd4324",

        # C4351: new behavior: elements of array 'array' will be default
        #        initialized
        # This is a silly "warning" that basically just alerts you that the
        # compiler is going to actually follow the language spec like it's
        # supposed to, instead of not following it like old buggy versions did.
        # There's absolutely no reason to turn this on.
        "/wd4351",

        # C4355: 'this': used in base member initializer list
        # It's commonly useful to pass |this| to objects in a class' initializer
        # list.  While this warning can catch real bugs, most of the time the
        # constructors in question don't attempt to call methods on the passed-in
        # pointer (until later), and annotating every legit usage of this is
        # simply more hassle than the warning is worth.
        "/wd4355",

        # C4503: 'identifier': decorated name length exceeded, name was
        #        truncated
        # This only means that some long error messages might have truncated
        # identifiers in the presence of lots of templates.  It has no effect on
        # program correctness and there's no real reason to waste time trying to
        # prevent it.
        "/wd4503",

        # Warning C4589 says: "Constructor of abstract class ignores
        # initializer for virtual base class." Disable this warning because it
        # is flaky in VS 2015 RTM. It triggers on compiler generated
        # copy-constructors in some cases.
        "/wd4589",

        # C4611: interaction between 'function' and C++ object destruction is
        #        non-portable
        # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
        # suggests using exceptions instead of setjmp/longjmp for C++, but
        # Chromium code compiles without exception support.  We therefore have to
        # use setjmp/longjmp for e.g. JPEG decode error handling, which means we
        # have to turn off this warning (and be careful about how object
        # destruction happens in such cases).
        "/wd4611",

        # Warnings to evaluate and possibly fix/reenable later:

        "/wd4100",  # Unreferenced formal function parameter.
        "/wd4121",  # Alignment of a member was sensitive to packing.
        "/wd4244",  # Conversion: possible loss of data.
        "/wd4505",  # Unreferenced local function has been removed.
        "/wd4510",  # Default constructor could not be generated.
        "/wd4512",  # Assignment operator could not be generated.
        "/wd4610",  # Class can never be instantiated, constructor required.
        "/wd4838",  # Narrowing conversion. Doesn't seem to be very useful.
        "/wd4995",  # 'X': name was marked as #pragma deprecated
        "/wd4996",  # Deprecated function warning.

        # These are variable shadowing warnings that are new in VS2015. We
        # should work through these at some point -- they may be removed from
        # the RTM release in the /W4 set.
        "/wd4456",
        "/wd4457",
        "/wd4458",
        "/wd4459",

        # All of our compilers support the extensions below.
        "/wd4200",  # nonstandard extension used: zero-sized array in
                    # struct/union
        "/wd4201",  # nonstandard extension used: nameless struct/union
        "/wd4204",  # nonstandard extension used : non-constant aggregate
                    # initializer

        "/wd4221",  # nonstandard extension used : 'identifier' : cannot be
                    # initialized using address of automatic variable

        # http://crbug.com/588506 - Conversion suppressions waiting on Clang
        # -Wconversion.
        "/wd4245",  # 'conversion' : conversion from 'type1' to 'type2',
                    # signed/unsigned mismatch

        "/wd4267",  # 'var' : conversion from 'size_t' to 'type', possible loss
                    # of data

        "/wd4305",  # 'identifier' : truncation from 'type1' to 'type2'
        "/wd4389",  # 'operator' : signed/unsigned mismatch

        "/wd4702",  # unreachable code

        # http://crbug.com/848979 - MSVC is more conservative than Clang with
        # regards to variables initialized and consumed in different branches.
        "/wd4701",  # Potentially uninitialized local variable 'name' used
        "/wd4703",  # Potentially uninitialized local pointer variable 'name'
                    # used

        # http://crbug.com/848979 - Remaining Clang permitted warnings.
        "/wd4661",  # 'identifier' : no suitable definition provided for
                    # explicit
                    # template instantiation request

        "/wd4706",  # assignment within conditional expression
                    # MSVC is stricter and requires a boolean expression.

        "/wd4715",  # 'function' : not all control paths return a value'
                    # MSVC does not analyze switch (enum) for completeness.
      ]

      cflags_cc += [
        # Allow "noexcept" annotations even though we compile with exceptions
        # disabled.
        "/wd4577",
      ]

      if (current_cpu == "x86") {
        if (msvc_use_sse2) {
          cflags += [ "/arch:SSE2" ]
        }
      }
    }
  }

  if (is_clang) {
    # Override -Wno-c++11-narrowing.
    cflags += [ "-Wc++11-narrowing" ]

    # May flag some issues when converting int to size_t.
    cflags += [ "-Wtautological-unsigned-zero-compare" ]
  }

  if (!is_win && !is_clang) {
    cflags += [
      # Override -Wno-narrowing for GCC.
      "-Wnarrowing",

      # GCC assumes that control can get past an exhaustive switch and then
      # warns if there's no return there.
      "-Wno-return-type",
    ]
  }

  if (clang_use_chrome_plugins) {
    defines += [ "PDF_USE_CHROME_PLUGINS" ]

    # Catch misuse of C-style pointers.
    # TODO(crbug.com/1320670): enable for non-debug builds once this stops
    # interfering with code generation.
    # TODO(tsepez): enable for windows, too.
    if (is_debug && !is_win) {
      cflags += [
        "-Xclang",
        "-plugin-arg-raw-ptr-plugin",
        "-Xclang",
        "check-raw-ptr-fields",

        "-Xclang",
        "-plugin-arg-raw-ptr-plugin",
        "-Xclang",
        "raw-ptr-exclude-path=public",

        "-Xclang",
        "-plugin-arg-raw-ptr-plugin",
        "-Xclang",
        "raw-ptr-exclude-path=test",

        # TODO(tsepez): enforce raw_ref<> as well.
        # "-Xclang",
        # "-plugin-arg-raw-ptr-plugin",
        # "-Xclang",
        # "check-raw-ref-fields",
      ]
      defines += [ "PDF_ENABLE_UNOWNED_PTR_EXCLUSION" ]
    }

    # Catch misuse of cppgc in XFA.
    if (pdf_enable_xfa) {
      cflags += [
        "-Xclang",
        "-add-plugin",
        "-Xclang",
        "blink-gc-plugin",
      ]

      # Disable GC plugin forbidding off-heap collections of GCed:
      cflags += [
        "-Xclang",
        "-plugin-arg-blink-gc-plugin",
        "-Xclang",
        "disable-off-heap-collections-of-gced-check",
      ]
    }
  }
}

config("pdfium_implementation_config") {
  defines = [ "FPDF_IMPLEMENTATION" ]
  visibility = [ ":pdfium_public_headers" ]
}

config("pdfium_public_config") {
  defines = []

  if (pdf_enable_v8) {
    defines += [ "PDF_ENABLE_V8" ]

    if (pdf_enable_xfa) {
      defines += [ "PDF_ENABLE_XFA" ]
      if (pdf_enable_xfa_bmp) {
        defines += [ "PDF_ENABLE_XFA_BMP" ]
      }
      if (pdf_enable_xfa_gif) {
        defines += [ "PDF_ENABLE_XFA_GIF" ]
      }
      if (pdf_enable_xfa_png) {
        defines += [ "PDF_ENABLE_XFA_PNG" ]
      }
      if (pdf_enable_xfa_tiff) {
        defines += [ "PDF_ENABLE_XFA_TIFF" ]
      }
    }
  }

  if (pdf_use_skia) {
    defines += [ "PDF_USE_SKIA" ]
  }
}

config("pdfium_core_config") {
  cflags = []
  configs = [
    ":pdfium_common_config",
    ":pdfium_public_config",
    "//build/config/compiler:noshadowing",
  ]
  defines = []
  if (is_win) {
    cflags += [
      "/wd4324",
      "/wd4577",
    ]
  }
  if (is_clang) {
    cflags += [ "-Wcovered-switch-default" ]
  }
}

config("pdfium_strict_config") {
  configs = [
    ":pdfium_core_config",
    "//build/config/compiler:wexit_time_destructors",
    "//build/config/compiler:wglobal_constructors",
  ]
}

config("pdfium_noshorten_config") {
  cflags = []
  if (is_clang) {
    cflags += [ "-Wshorten-64-to-32" ]
  }
}

source_set("pdfium_public_headers_impl") {
  sources = [
    "public/cpp/fpdf_deleters.h",
    "public/cpp/fpdf_scopers.h",
    "public/fpdf_annot.h",
    "public/fpdf_attachment.h",
    "public/fpdf_catalog.h",
    "public/fpdf_dataavail.h",
    "public/fpdf_doc.h",
    "public/fpdf_edit.h",
    "public/fpdf_ext.h",
    "public/fpdf_flatten.h",
    "public/fpdf_formfill.h",
    "public/fpdf_fwlevent.h",
    "public/fpdf_javascript.h",
    "public/fpdf_ppo.h",
    "public/fpdf_progressive.h",
    "public/fpdf_save.h",
    "public/fpdf_searchex.h",
    "public/fpdf_signature.h",
    "public/fpdf_structtree.h",
    "public/fpdf_sysfontinfo.h",
    "public/fpdf_text.h",
    "public/fpdf_transformpage.h",
    "public/fpdfview.h",
  ]
}

group("pdfium_public_headers") {
  public_deps = [ ":pdfium_public_headers_impl" ]
  public_configs = [
    ":pdfium_public_config",
    ":pdfium_implementation_config",
  ]
}

component("pdfium") {
  output_name = "pdfium"
  libs = []
  configs += [ ":pdfium_strict_config" ]
  public_configs = [ ":pdfium_public_config" ]

  deps = [
    "constants",
    "core/fpdfapi/page",
    "core/fpdfapi/parser",
    "core/fpdfdoc",
    "core/fxcodec",
    "core/fxcrt",
    "core/fxge",
    "fpdfsdk",
    "fpdfsdk/formfiller",
    "fxjs",
  ]

  public_deps = [
    ":pdfium_public_headers_impl",
    "core/fxcrt",
  ]

  if (pdf_enable_xfa) {
    deps += [
      "fpdfsdk/fpdfxfa",
      "xfa/fxfa",
      "xfa/fxfa/parser",
    ]
  }

  if (is_win) {
    libs += [
      "advapi32.lib",
      "gdi32.lib",
      "user32.lib",
    ]
  }

  if (is_mac) {
    frameworks = [
      "AppKit.framework",
      "CoreFoundation.framework",
    ]
  }

  if (pdf_is_complete_lib) {
    static_component_type = "static_library"
    complete_static_lib = true
    configs -= [ "//build/config/compiler:thin_archive" ]
  }
}

# Targets below this are only visible within this file.
visibility = [ ":*" ]

group("pdfium_unittest_deps") {
  testonly = true
  public_deps = [
    "core/fxcrt",
    "testing:unit_test_support",
    "//testing/gmock",
    "//testing/gtest",
  ]
  visibility += [
    "core/*",
    "fpdfsdk/*",
    "fxbarcode/*",
    "fxjs/*",
    "xfa/*",
  ]
}

test("pdfium_unittests") {
  testonly = true
  sources = [ "testing/unit_test_main.cpp" ]
  deps = [
    "core/fdrm:unittests",
    "core/fpdfapi/edit:unittests",
    "core/fpdfapi/font:unittests",
    "core/fpdfapi/page:unittests",
    "core/fpdfapi/parser:unittests",
    "core/fpdfapi/render:unittests",
    "core/fpdfdoc:unittests",
    "core/fpdftext:unittests",
    "core/fxcodec:unittests",
    "core/fxcrt",
    "core/fxcrt:unittests",
    "core/fxge:unittests",
    "fpdfsdk:unittests",
    "testing:unit_test_support",
    "//testing/gmock",
    "//testing/gtest",
  ]
  configs += [ ":pdfium_core_config" ]
  if (is_android) {
    use_raw_android_executable = true
  }
  if (pdf_enable_v8) {
    configs += [ "//v8:external_startup_data" ]
    deps += [
      "fxjs:unittests",
      "//v8",
    ]
    if (pdf_enable_xfa) {
      deps += [
        "core/fxcrt/css:unittests",
        "fxbarcode:unittests",
        "xfa/fde:unittests",
        "xfa/fgas/crt:unittests",
        "xfa/fgas/font:unittests",
        "xfa/fgas/layout:unittests",
        "xfa/fxfa:unittests",
        "xfa/fxfa/formcalc:unittests",
        "xfa/fxfa/parser:unittests",
      ]
    }
  }
}

group("pdfium_embeddertest_deps") {
  testonly = true
  public_deps = [
    ":pdfium_public_headers",
    "core/fxcrt",
    "testing:embedder_test_support",
    "//testing/gmock",
    "//testing/gtest",
  ]
  visibility += [
    "core/*",
    "fpdfsdk/*",
    "fxjs/*",
    "xfa/*",
  ]
}

test("pdfium_embeddertests") {
  testonly = true
  sources = [ "testing/embedder_test_main.cpp" ]
  deps = [
    ":pdfium_embeddertest_deps",
    "core/fpdfapi/edit:embeddertests",
    "core/fpdfapi/parser:embeddertests",
    "core/fpdfapi/render:embeddertests",
    "core/fxcodec:embeddertests",
    "core/fxcrt",
    "core/fxge:embeddertests",
    "fpdfsdk:embeddertests",
    "fpdfsdk/formfiller:embeddertests",
    "fpdfsdk/pwl:embeddertests",
    "testing/image_diff",
    "//testing/gmock",
    "//testing/gtest",
  ]
  include_dirs = [ "testing/gmock/include" ]
  configs += [ ":pdfium_core_config" ]

  if (is_android) {
    ignore_all_data_deps = true
    use_raw_android_executable = true
  }

  if (pdf_enable_v8) {
    deps += [
      "fxjs:embeddertests",
      "//v8",
    ]
    configs += [ "//v8:external_startup_data" ]
  }

  if (pdf_enable_xfa) {
    deps += [
      "fpdfsdk/fpdfxfa:embeddertests",
      "xfa/fwl:embeddertests",
      "xfa/fxfa/layout:embeddertests",
      "xfa/fxfa/parser:embeddertests",
    ]
  }
}

executable("pdfium_diff") {
  visibility += [ "testing/tools:test_runner_py" ]
  testonly = true
  sources = [ "testing/image_diff/image_diff.cpp" ]
  deps = [
    "core/fxcrt",
    "testing:path_service",
    "testing/image_diff",
    "//build/win:default_exe_manifest",
  ]
  configs += [ ":pdfium_strict_config" ]
}

group("pdfium_all") {
  testonly = true
  deps = [
    ":pdfium_diff",
    ":pdfium_embeddertests",
    ":pdfium_unittests",
    "testing:pdfium_test",
    "testing/fuzzers",
  ]

  if (pdf_is_standalone) {
    deps += [ "testing/tools:test_runner_py" ]
  }
}

# Makes additional targets reachable only for "gn check". These are not always
# built by the "all" Ninja target, which uses the "default" group, which in turn
# depends on the "pdfium_all" group.
group("gn_check") {
  deps = []

  # TODO(crbug.com/pdfium/1832): Remove !is_android when //third_party/expat is
  # available.
  if (defined(checkout_skia) && checkout_skia && !is_android) {
    deps += [ "//skia" ]
  }
}
