blob: 4b100243dd7160b9fe913bac8332e910abc6d037 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DisplayItemClient_h
#define DisplayItemClient_h
#include "platform/PlatformExport.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/graphics/PaintInvalidationReason.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/text/WTFString.h"
#define CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS DCHECK_IS_ON()
namespace blink {
// The class for objects that can be associated with display items. A
// DisplayItemClient object should live at least longer than the document cycle
// in which its display items are created during painting. After the document
// cycle, a pointer/reference to DisplayItemClient should be no longer
// dereferenced unless we can make sure the client is still valid.
class PLATFORM_EXPORT DisplayItemClient {
public:
#if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
DisplayItemClient();
virtual ~DisplayItemClient();
// Tests if this DisplayItemClient object has been created and has not been
// deleted yet.
bool IsAlive() const;
// Called when any DisplayItem of this DisplayItemClient is added into
// PaintController using PaintController::createAndAppend() or into a cached
// subsequence.
void BeginShouldKeepAlive(const void* owner) const;
// Called when the DisplayItemClient is sure that it can safely die before its
// owners have chance to remove it from the aliveness control.
void EndShouldKeepAlive() const;
// Clears all should-keep-alive DisplayItemClients of a PaintController.
// Called after PaintController commits new display items or the subsequence
// owner is invalidated.
static void EndShouldKeepAliveAllClients(const void* owner);
static void EndShouldKeepAliveAllClients();
#else
DisplayItemClient() {}
virtual ~DisplayItemClient() {}
#endif
virtual String DebugName() const = 0;
// The visual rect of this DisplayItemClient, in the object space of the
// object that owns the GraphicsLayer, i.e. offset by
// GraphicsLayer::OffsetFromLayoutObjectWithSubpixelAccumulation().
virtual LayoutRect VisualRect() const = 0;
// This is declared here instead of in LayoutObject for verifying the
// condition in DrawingRecorder.
// Returns true if the object itself will not generate any effective painted
// output no matter what size the object is. For example, this function can
// return false for an object whose size is currently 0x0 but would have
// effective painted output if it was set a non-empty size. It's used to skip
// unforced paint invalidation of LayoutObjects (which is when
// shouldDoFullPaintInvalidation is false, but mayNeedPaintInvalidation or
// childShouldCheckForPaintInvalidation is true) to avoid unnecessary paint
// invalidations of empty areas covered by such objects.
virtual bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
return false;
}
void SetDisplayItemsUncached(
PaintInvalidationReason reason = PaintInvalidationReason::kFull) const {
cache_generation_or_invalidation_reason_.Invalidate(reason);
#if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
// Clear should-keep-alive of DisplayItemClients in a subsequence if this
// object is a subsequence.
EndShouldKeepAliveAllClients(this);
#endif
}
PaintInvalidationReason GetPaintInvalidationReason() const {
return cache_generation_or_invalidation_reason_
.GetPaintInvalidationReason();
}
// A client is considered "just created" if its display items have never been
// committed.
bool IsJustCreated() const {
return cache_generation_or_invalidation_reason_.IsJustCreated();
}
void ClearIsJustCreated() const {
cache_generation_or_invalidation_reason_.ClearIsJustCreated();
}
private:
friend class FakeDisplayItemClient;
friend class PaintController;
// Holds a unique cache generation id of DisplayItemClients and
// PaintControllers, or PaintInvalidationReason if the DisplayItemClient or
// PaintController is invalidated.
//
// A paint controller sets its cache generation to
// DisplayItemCacheGeneration::next() at the end of each
// commitNewDisplayItems, and updates the cache generation of each client with
// cached drawings by calling DisplayItemClient::setDisplayItemsCached(). A
// display item is treated as validly cached in a paint controller if its
// cache generation matches the paint controller's cache generation.
//
// SPv1 only: If a display item is painted on multiple paint controllers,
// because cache generations are unique, the client's cache generation matches
// the last paint controller only. The client will be treated as invalid on
// other paint controllers regardless if it's validly cached by these paint
// controllers. This situation is very rare (about 0.07% of clients were
// painted on multiple paint controllers) so the performance penalty is
// trivial.
class PLATFORM_EXPORT CacheGenerationOrInvalidationReason {
DISALLOW_NEW();
public:
CacheGenerationOrInvalidationReason() : value_(kJustCreated) {}
void Invalidate(
PaintInvalidationReason reason = PaintInvalidationReason::kFull) {
if (value_ != kJustCreated)
value_ = static_cast<ValueType>(reason);
}
static CacheGenerationOrInvalidationReason Next() {
// In case the value overflowed in the previous call.
if (next_generation_ < kFirstValidGeneration)
next_generation_ = kFirstValidGeneration;
return CacheGenerationOrInvalidationReason(next_generation_++);
}
bool Matches(const CacheGenerationOrInvalidationReason& other) const {
return value_ >= kFirstValidGeneration &&
other.value_ >= kFirstValidGeneration && value_ == other.value_;
}
PaintInvalidationReason GetPaintInvalidationReason() const {
if (value_ == kJustCreated)
return PaintInvalidationReason::kAppeared;
if (value_ < kJustCreated)
return static_cast<PaintInvalidationReason>(value_);
return PaintInvalidationReason::kNone;
}
bool IsJustCreated() const { return value_ == kJustCreated; }
void ClearIsJustCreated() {
value_ = static_cast<ValueType>(PaintInvalidationReason::kFull);
}
private:
typedef uint32_t ValueType;
explicit CacheGenerationOrInvalidationReason(ValueType value)
: value_(value) {}
static const ValueType kJustCreated =
static_cast<ValueType>(PaintInvalidationReason::kMax) + 1;
static const ValueType kFirstValidGeneration =
static_cast<ValueType>(PaintInvalidationReason::kMax) + 2;
static ValueType next_generation_;
ValueType value_;
};
bool DisplayItemsAreCached(CacheGenerationOrInvalidationReason other) const {
return cache_generation_or_invalidation_reason_.Matches(other);
}
void SetDisplayItemsCached(
CacheGenerationOrInvalidationReason cache_generation) const {
cache_generation_or_invalidation_reason_ = cache_generation;
}
mutable CacheGenerationOrInvalidationReason
cache_generation_or_invalidation_reason_;
DISALLOW_COPY_AND_ASSIGN(DisplayItemClient);
};
inline bool operator==(const DisplayItemClient& client1,
const DisplayItemClient& client2) {
return &client1 == &client2;
}
inline bool operator!=(const DisplayItemClient& client1,
const DisplayItemClient& client2) {
return &client1 != &client2;
}
} // namespace blink
#endif // DisplayItemClient_h