/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* C++ types corresponding to Servo and Gecko types used across bindings,
   with some annotations to indicate ownership expectations */

// This file defines RefPtrTraits and UniquePtrTraits helpers for a number of
// C++ types used to represent strong, and owning references to Servo and Gecko
// objects that might be used across bindings and FFI.
//
// The strong, and owned reference types should be used in FFI function
// signatures where possible, to help indicate the ownership properties that
// both sides of the function call must adhere to.
//
// Using these types in C++ ========================
//
// The Strong types are a C++ struct that wraps a raw pointer.  When receiving a
// Strong value from a Servo_* FFI function, you must call Consume() on it to
// convert it into an already_AddRefed<RawServo{Type}>, otherwise it will leak.
//
// We don't currently have any cases where we pass a Strong value to Servo; this
// could be done by creating a RawServo{Type}Strong struct value whose mPtr is
// initialized to the result of calling `.forget().take()` on a
// RefPtr<RawServo{Type}>, but it's probably easier just to pass a raw pointer
// and let the Rust code turn it into an Arc.
//
// TODO(heycam): We should perhaps have a similar struct for Owned types with a
// Consume() method to convert them into a UniquePtr.  The struct for Strong
// types at least have [[nodiscard]] on them.
//
// Using these types in Rust =========================
//
// The FFI type names are available in Rust in the gecko_bindings::bindings mod,
// which is generated by servo/components/style/build_gecko.rs.
//
// Borrowed types in rust are represented by &T, Option<&T>, &mut T, and
// Option<&mut T>.
//
// In C++ you should write them as const pointers (for &T and Option<&T>) or
// non-const pointers (for &mut T and Option<&mut T>).
//
// The Strong types are defined as gecko_bindings::sugar::ownership::Strong<T>.
//
// This is an FFI safe type that represents the value with a strong reference
// already added to it.  Dropping a Strong<T> will leak the strong reference.
//
// The Owned types are defined as gecko_bindings::sugar::ownership::Owned<T>
// (or OwnedOrNull<T>). This is another FFI safe type that represents the owning
// reference to the value.  Dropping an Owned<T> will leak the value.

#ifndef mozilla_ServoBindingTypes_h
#define mozilla_ServoBindingTypes_h

#include "mozilla/RefPtr.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/Types.h"
#include "nsCSSPropertyID.h"
#include "nsStyleAutoArray.h"
#include "nsTArray.h"

// Forward declarations.

class nsCSSPropertyIDSet;
class nsCSSValue;
class nsINode;
class nsPresContext;
struct nsFontFaceRuleContainer;

namespace mozilla {
class ComputedStyle;
class ServoElementSnapshot;
struct AnimationPropertySegment;
struct ComputedTiming;
struct Keyframe;
struct PropertyStyleAnimationValuePair;
struct PropertyValuePair;
struct StyleAnimation;
struct StyleCssUrlData;
struct StyleAnimationValue;
struct StyleStylesheetContents;
struct URLExtraData;
using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
using GfxMatrix4x4 = mozilla::gfx::Float[16];

namespace dom {
class StyleChildrenIterator;
class Document;
class Element;
}  // namespace dom

}  // namespace mozilla

#define SERVO_ARC_TYPE(name_, type_)                                    \
  extern "C" {                                                          \
  void Servo_##name_##_AddRef(const type_*);                            \
  void Servo_##name_##_Release(const type_*);                           \
  }                                                                     \
  namespace mozilla {                                                   \
  template <>                                                           \
  struct RefPtrTraits<type_> {                                          \
    static void AddRef(type_* aPtr) { Servo_##name_##_AddRef(aPtr); }   \
    static void Release(type_* aPtr) { Servo_##name_##_Release(aPtr); } \
  };                                                                    \
  }
#define SERVO_LOCKED_ARC_TYPE(name_) \
  namespace mozilla {                \
  struct StyleLocked##name_;         \
  }                                  \
  SERVO_ARC_TYPE(name_, mozilla::StyleLocked##name_)
#include "mozilla/ServoLockedArcTypeList.h"

#define UNLOCKED_RULE_TYPE(name_) \
  namespace mozilla {             \
  struct Style##name_##Rule;      \
  }                               \
  SERVO_ARC_TYPE(name_##Rule, mozilla::Style##name_##Rule)

UNLOCKED_RULE_TYPE(Property)
UNLOCKED_RULE_TYPE(LayerBlock)
UNLOCKED_RULE_TYPE(LayerStatement)
UNLOCKED_RULE_TYPE(Namespace)
UNLOCKED_RULE_TYPE(Margin)
UNLOCKED_RULE_TYPE(Container)
UNLOCKED_RULE_TYPE(Media)
UNLOCKED_RULE_TYPE(Supports)
UNLOCKED_RULE_TYPE(Document)
UNLOCKED_RULE_TYPE(FontFeatureValues)
UNLOCKED_RULE_TYPE(FontPaletteValues)
UNLOCKED_RULE_TYPE(Scope)
UNLOCKED_RULE_TYPE(StartingStyle)

SERVO_ARC_TYPE(AnimationValue, mozilla::StyleAnimationValue)
SERVO_ARC_TYPE(ComputedStyle, mozilla::ComputedStyle)
SERVO_ARC_TYPE(CssUrlData, mozilla::StyleCssUrlData)
SERVO_ARC_TYPE(StyleSheetContents, mozilla::StyleStylesheetContents)

#undef UNLOCKED_RULE_TYPE
#undef SERVO_LOCKED_ARC_TYPE
#undef SERVO_ARC_TYPE

#define SERVO_BOXED_TYPE(name_, type_)                                        \
  namespace mozilla {                                                         \
  struct Style##type_;                                                        \
  }                                                                           \
  extern "C" void Servo_##name_##_Drop(mozilla::Style##type_*);               \
  namespace mozilla {                                                         \
  template <>                                                                 \
  class DefaultDelete<Style##type_> {                                         \
   public:                                                                    \
    void operator()(Style##type_* aPtr) const { Servo_##name_##_Drop(aPtr); } \
  };                                                                          \
  }
#include "mozilla/ServoBoxedTypeList.h"
#undef SERVO_BOXED_TYPE

// Other special cases.

struct RawServoAnimationValueTable;

#endif  // mozilla_ServoBindingTypes_h
