Format the world (or just HWUI)
Test: No code changes, just ran through clang-format
Change-Id: Id23aa4ec7eebc0446fe3a30260f33e7fd455bb8c
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 4b80542..7f75609 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_HWUI_VPATH_H
#define ANDROID_HWUI_VPATH_H
-#include "hwui/Canvas.h"
-#include "hwui/Bitmap.h"
-#include "renderthread/CacheManager.h"
#include "DisplayList.h"
+#include "hwui/Bitmap.h"
+#include "hwui/Canvas.h"
+#include "renderthread/CacheManager.h"
#include <SkBitmap.h>
+#include <SkCanvas.h>
#include <SkColor.h>
#include <SkColorFilter.h>
-#include <SkCanvas.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPath.h>
@@ -36,25 +36,35 @@
#include <cutils/compiler.h>
#include <stddef.h>
-#include <vector>
#include <string>
+#include <vector>
namespace android {
namespace uirenderer {
// Debug
#if DEBUG_VECTOR_DRAWABLE
- #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
+#define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define VECTOR_DRAWABLE_LOGD(...)
+#define VECTOR_DRAWABLE_LOGD(...)
#endif
namespace VectorDrawable {
-#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) \
+ (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
-#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
- onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) \
+ ({ \
+ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value)); \
+ onPropertyChanged(); \
+ retVal; \
+ })
+#define UPDATE_SKPROP(field, value) \
+ ({ \
+ bool retVal = ((field) != (value)); \
+ if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); \
+ retVal; \
+ })
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -85,12 +95,9 @@
public:
PropertyChangedListener(bool* dirty, bool* stagingDirty)
: mDirty(dirty), mStagingDirty(stagingDirty) {}
- void onPropertyChanged() {
- *mDirty = true;
- }
- void onStagingPropertyChanged() {
- *mStagingDirty = true;
- }
+ void onPropertyChanged() { *mDirty = true; }
+ void onStagingPropertyChanged() { *mStagingDirty = true; }
+
private:
bool* mDirty;
bool* mStagingDirty;
@@ -101,27 +108,23 @@
class Properties {
public:
explicit Properties(Node* node) : mNode(node) {}
- inline void onPropertyChanged() {
- mNode->onPropertyChanged(this);
- }
+ inline void onPropertyChanged() { mNode->onPropertyChanged(this); }
+
private:
Node* mNode;
};
- Node(const Node& node) {
- mName = node.mName;
- }
+ Node(const Node& node) { mName = node.mName; }
Node() {}
virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0;
virtual void dump() = 0;
- void setName(const char* name) {
- mName = name;
- }
+ void setName(const char* name) { mName = name; }
virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
mPropertyChangedListener = listener;
}
virtual void onPropertyChanged(Properties* properties) = 0;
- virtual ~Node(){}
+ virtual ~Node() {}
virtual void syncProperties() = 0;
+
protected:
std::string mName;
PropertyChangedListener* mPropertyChangedListener = nullptr;
@@ -134,8 +137,7 @@
std::vector<size_t> verbSizes;
std::vector<float> points;
bool operator==(const Data& data) const {
- return verbs == data.verbs && verbSizes == data.verbSizes
- && points == data.points;
+ return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
}
};
@@ -156,11 +158,9 @@
}
mData = data;
onPropertyChanged();
+ }
+ const Data& getData() const { return mData; }
- }
- const Data& getData() const {
- return mData;
- }
private:
Data mData;
};
@@ -177,7 +177,7 @@
if (mPropertyChangedListener) {
mPropertyChangedListener->onStagingPropertyChanged();
}
- } else if (prop == &mProperties){
+ } else if (prop == &mProperties) {
mSkPathDirty = true;
if (mPropertyChangedListener) {
mPropertyChangedListener->onPropertyChanged();
@@ -203,7 +203,7 @@
bool mStagingPropertiesDirty = true;
};
-class ANDROID_API FullPath: public Path {
+class ANDROID_API FullPath : public Path {
public:
class FullPathProperties : public Properties {
public:
@@ -234,87 +234,59 @@
onPropertyChanged();
}
void setFillGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(fillGradient, gradient)) {
+ if (UPDATE_SKPROP(fillGradient, gradient)) {
onPropertyChanged();
}
}
void setStrokeGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(strokeGradient, gradient)) {
+ if (UPDATE_SKPROP(strokeGradient, gradient)) {
onPropertyChanged();
}
}
- SkShader* getFillGradient() const {
- return fillGradient;
- }
- SkShader* getStrokeGradient() const {
- return strokeGradient;
- }
- float getStrokeWidth() const{
- return mPrimitiveFields.strokeWidth;
- }
+ SkShader* getFillGradient() const { return fillGradient; }
+ SkShader* getStrokeGradient() const { return strokeGradient; }
+ float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
}
- SkColor getStrokeColor() const{
- return mPrimitiveFields.strokeColor;
- }
+ SkColor getStrokeColor() const { return mPrimitiveFields.strokeColor; }
void setStrokeColor(SkColor strokeColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
}
- float getStrokeAlpha() const{
- return mPrimitiveFields.strokeAlpha;
- }
+ float getStrokeAlpha() const { return mPrimitiveFields.strokeAlpha; }
void setStrokeAlpha(float strokeAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
}
- SkColor getFillColor() const {
- return mPrimitiveFields.fillColor;
- }
+ SkColor getFillColor() const { return mPrimitiveFields.fillColor; }
void setFillColor(SkColor fillColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
}
- float getFillAlpha() const{
- return mPrimitiveFields.fillAlpha;
- }
+ float getFillAlpha() const { return mPrimitiveFields.fillAlpha; }
void setFillAlpha(float fillAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
}
- float getTrimPathStart() const{
- return mPrimitiveFields.trimPathStart;
- }
+ float getTrimPathStart() const { return mPrimitiveFields.trimPathStart; }
void setTrimPathStart(float trimPathStart) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
}
- float getTrimPathEnd() const{
- return mPrimitiveFields.trimPathEnd;
- }
+ float getTrimPathEnd() const { return mPrimitiveFields.trimPathEnd; }
void setTrimPathEnd(float trimPathEnd) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
}
- float getTrimPathOffset() const{
- return mPrimitiveFields.trimPathOffset;
- }
+ float getTrimPathOffset() const { return mPrimitiveFields.trimPathOffset; }
void setTrimPathOffset(float trimPathOffset) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
}
- float getStrokeMiterLimit() const {
- return mPrimitiveFields.strokeMiterLimit;
- }
- float getStrokeLineCap() const {
- return mPrimitiveFields.strokeLineCap;
- }
- float getStrokeLineJoin() const {
- return mPrimitiveFields.strokeLineJoin;
- }
- float getFillType() const {
- return mPrimitiveFields.fillType;
- }
+ float getStrokeMiterLimit() const { return mPrimitiveFields.strokeMiterLimit; }
+ float getStrokeLineCap() const { return mPrimitiveFields.strokeLineCap; }
+ float getStrokeLineJoin() const { return mPrimitiveFields.strokeLineJoin; }
+ float getFillType() const { return mPrimitiveFields.fillType; }
bool copyProperties(int8_t* outProperties, int length) const;
void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
- SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
- int fillType) {
+ SkColor fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit,
+ int strokeLineCap, int strokeLineJoin, int fillType) {
mPrimitiveFields.strokeWidth = strokeWidth;
mPrimitiveFields.strokeColor = strokeColor;
mPrimitiveFields.strokeAlpha = strokeAlpha;
@@ -334,6 +306,7 @@
void setColorPropertyValue(int propertyId, int32_t value);
void setPropertyValue(int propertyId, float value);
bool mTrimDirty;
+
private:
enum class Property {
strokeWidth = 0,
@@ -356,7 +329,7 @@
};
// Called from UI thread
- FullPath(const FullPath& path); // for cloning
+ FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
void draw(SkCanvas* outCanvas, bool useStagingData) override;
@@ -384,18 +357,17 @@
protected:
const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
-private:
+private:
FullPathProperties mProperties = FullPathProperties(this);
FullPathProperties mStagingProperties = FullPathProperties(this);
bool mStagingPropertiesDirty = true;
// Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
-
};
-class ANDROID_API ClipPath: public Path {
+class ANDROID_API ClipPath : public Path {
public:
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
@@ -403,7 +375,7 @@
void draw(SkCanvas* outCanvas, bool useStagingData) override;
};
-class ANDROID_API Group: public Node {
+class ANDROID_API Group : public Node {
public:
class GroupProperties : public Properties {
public:
@@ -421,50 +393,26 @@
mPrimitiveFields = prop.mPrimitiveFields;
onPropertyChanged();
}
- float getRotation() const {
- return mPrimitiveFields.rotate;
- }
- void setRotation(float rotation) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
- }
- float getPivotX() const {
- return mPrimitiveFields.pivotX;
- }
- void setPivotX(float pivotX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
- }
- float getPivotY() const {
- return mPrimitiveFields.pivotY;
- }
- void setPivotY(float pivotY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
- }
- float getScaleX() const {
- return mPrimitiveFields.scaleX;
- }
- void setScaleX(float scaleX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
- }
- float getScaleY() const {
- return mPrimitiveFields.scaleY;
- }
- void setScaleY(float scaleY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
- }
- float getTranslateX() const {
- return mPrimitiveFields.translateX;
- }
+ float getRotation() const { return mPrimitiveFields.rotate; }
+ void setRotation(float rotation) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); }
+ float getPivotX() const { return mPrimitiveFields.pivotX; }
+ void setPivotX(float pivotX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); }
+ float getPivotY() const { return mPrimitiveFields.pivotY; }
+ void setPivotY(float pivotY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); }
+ float getScaleX() const { return mPrimitiveFields.scaleX; }
+ void setScaleX(float scaleX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); }
+ float getScaleY() const { return mPrimitiveFields.scaleY; }
+ void setScaleY(float scaleY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); }
+ float getTranslateX() const { return mPrimitiveFields.translateX; }
void setTranslateX(float translateX) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
}
- float getTranslateY() const {
- return mPrimitiveFields.translateY;
- }
+ float getTranslateY() const { return mPrimitiveFields.translateY; }
void setTranslateY(float translateY) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
}
- void updateProperties(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY) {
+ void updateProperties(float rotate, float pivotX, float pivotY, float scaleX, float scaleY,
+ float translateX, float translateY) {
mPrimitiveFields.rotate = rotate;
mPrimitiveFields.pivotX = pivotX;
mPrimitiveFields.pivotY = pivotY;
@@ -478,6 +426,7 @@
float getPropertyValue(int propertyId) const;
bool copyProperties(float* outProperties, int length) const;
static bool isValidProperty(int propertyId);
+
private:
enum class Property {
rotate = 0,
@@ -498,7 +447,7 @@
virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
Node::setPropertyChangedListener(listener);
for (auto& child : mChildren) {
- child->setPropertyChangedListener(listener);
+ child->setPropertyChangedListener(listener);
}
}
virtual void syncProperties() override;
@@ -531,7 +480,7 @@
GroupProperties mProperties = GroupProperties(this);
GroupProperties mStagingProperties = GroupProperties(this);
bool mStagingPropertiesDirty = true;
- std::vector< std::unique_ptr<Node> > mChildren;
+ std::vector<std::unique_ptr<Node> > mChildren;
};
class ANDROID_API Tree : public VirtualLightRefBase {
@@ -547,27 +496,25 @@
}
// Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
// canvas. Returns the number of pixels needed for the bitmap cache.
- int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
- const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ int draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
+ bool needsMirroring, bool canReuseCache);
void drawStaging(Canvas* canvas);
Bitmap& getBitmapUpdateIfDirty();
- void setAllowCaching(bool allowCaching) {
- mAllowCaching = allowCaching;
- }
+ void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
SkPaint* getPaint();
void syncProperties() {
if (mStagingProperties.mNonAnimatablePropertiesDirty) {
- mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth
- != mStagingProperties.mNonAnimatableProperties.viewportWidth)
- || (mProperties.mNonAnimatableProperties.viewportHeight
- != mStagingProperties.mNonAnimatableProperties.viewportHeight)
- || (mProperties.mNonAnimatableProperties.scaledWidth
- != mStagingProperties.mNonAnimatableProperties.scaledWidth)
- || (mProperties.mNonAnimatableProperties.scaledHeight
- != mStagingProperties.mNonAnimatableProperties.scaledHeight)
- || (mProperties.mNonAnimatableProperties.bounds
- != mStagingProperties.mNonAnimatableProperties.bounds);
+ mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
+ mStagingProperties.mNonAnimatableProperties.viewportWidth) ||
+ (mProperties.mNonAnimatableProperties.viewportHeight !=
+ mStagingProperties.mNonAnimatableProperties.viewportHeight) ||
+ (mProperties.mNonAnimatableProperties.scaledWidth !=
+ mStagingProperties.mNonAnimatableProperties.scaledWidth) ||
+ (mProperties.mNonAnimatableProperties.scaledHeight !=
+ mStagingProperties.mNonAnimatableProperties.scaledHeight) ||
+ (mProperties.mNonAnimatableProperties.bounds !=
+ mStagingProperties.mNonAnimatableProperties.bounds);
mProperties.syncNonAnimatableProperties(mStagingProperties);
mStagingProperties.mNonAnimatablePropertiesDirty = false;
}
@@ -593,9 +540,7 @@
int scaledWidth = 0;
int scaledHeight = 0;
SkColorFilter* colorFilter = nullptr;
- ~NonAnimatableProperties() {
- SkSafeUnref(colorFilter);
- }
+ ~NonAnimatableProperties() { SkSafeUnref(colorFilter); }
} mNonAnimatableProperties;
bool mNonAnimatablePropertiesDirty = true;
@@ -606,14 +551,14 @@
// Copy over the data that can only be changed in UI thread
if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
- prop.mNonAnimatableProperties.colorFilter);
+ prop.mNonAnimatableProperties.colorFilter);
}
mNonAnimatableProperties = prop.mNonAnimatableProperties;
}
void setViewportSize(float width, float height) {
- if (mNonAnimatableProperties.viewportWidth != width
- || mNonAnimatableProperties.viewportHeight != height) {
+ if (mNonAnimatableProperties.viewportWidth != width ||
+ mNonAnimatableProperties.viewportHeight != height) {
mNonAnimatablePropertiesDirty = true;
mNonAnimatableProperties.viewportWidth = width;
mNonAnimatableProperties.viewportHeight = height;
@@ -632,12 +577,12 @@
// If the requested size is bigger than what the bitmap was, then
// we increase the bitmap size to match. The width and height
// are bound by MAX_CACHED_BITMAP_SIZE.
- if (mNonAnimatableProperties.scaledWidth < width
- || mNonAnimatableProperties.scaledHeight < height) {
- mNonAnimatableProperties.scaledWidth = std::max(width,
- mNonAnimatableProperties.scaledWidth);
- mNonAnimatableProperties.scaledHeight = std::max(height,
- mNonAnimatableProperties.scaledHeight);
+ if (mNonAnimatableProperties.scaledWidth < width ||
+ mNonAnimatableProperties.scaledHeight < height) {
+ mNonAnimatableProperties.scaledWidth =
+ std::max(width, mNonAnimatableProperties.scaledWidth);
+ mNonAnimatableProperties.scaledHeight =
+ std::max(height, mNonAnimatableProperties.scaledHeight);
mNonAnimatablePropertiesDirty = true;
mTree->onPropertyChanged(this);
}
@@ -648,25 +593,13 @@
mTree->onPropertyChanged(this);
}
}
- SkColorFilter* getColorFilter() const{
- return mNonAnimatableProperties.colorFilter;
- }
+ SkColorFilter* getColorFilter() const { return mNonAnimatableProperties.colorFilter; }
- float getViewportWidth() const {
- return mNonAnimatableProperties.viewportWidth;
- }
- float getViewportHeight() const {
- return mNonAnimatableProperties.viewportHeight;
- }
- float getScaledWidth() const {
- return mNonAnimatableProperties.scaledWidth;
- }
- float getScaledHeight() const {
- return mNonAnimatableProperties.scaledHeight;
- }
- void syncAnimatableProperties(const TreeProperties& prop) {
- mRootAlpha = prop.mRootAlpha;
- }
+ float getViewportWidth() const { return mNonAnimatableProperties.viewportWidth; }
+ float getViewportHeight() const { return mNonAnimatableProperties.viewportHeight; }
+ float getScaledWidth() const { return mNonAnimatableProperties.scaledWidth; }
+ float getScaledHeight() const { return mNonAnimatableProperties.scaledHeight; }
+ void syncAnimatableProperties(const TreeProperties& prop) { mRootAlpha = prop.mRootAlpha; }
bool setRootAlpha(float rootAlpha) {
if (rootAlpha != mRootAlpha) {
mAnimatablePropertiesDirty = true;
@@ -676,10 +609,8 @@
}
return false;
}
- float getRootAlpha() const { return mRootAlpha;}
- const SkRect& getBounds() const {
- return mNonAnimatableProperties.bounds;
- }
+ float getRootAlpha() const { return mRootAlpha; }
+ const SkRect& getBounds() const { return mNonAnimatableProperties.bounds; }
Tree* mTree;
};
void onPropertyChanged(TreeProperties* prop);
@@ -713,8 +644,8 @@
private:
class Cache {
public:
- sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
- //TODO: use surface instead of bitmap when drawing in software canvas
+ sk_sp<Bitmap> bitmap; // used by HWUI pipeline and software
+ // TODO: use surface instead of bitmap when drawing in software canvas
bool dirty = true;
// the rest of the code in Cache is used by Skia pipelines only
@@ -725,7 +656,7 @@
* Stores a weak pointer to the atlas and a key.
*/
void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
- skiapipeline::AtlasKey newAtlasKey);
+ skiapipeline::AtlasKey newAtlasKey);
/**
* Gets a surface and bounds from the atlas.
@@ -738,6 +669,7 @@
* Releases atlas key from the atlas, which makes it available for reuse.
*/
void clear();
+
private:
wp<skiapipeline::VectorDrawableAtlas> mAtlas;
skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
@@ -764,16 +696,16 @@
Cache mStagingCache;
Cache mCache;
- PropertyChangedListener mPropertyChangedListener
- = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+ PropertyChangedListener mPropertyChangedListener =
+ PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
mutable bool mWillBeConsumed = false;
};
-} // namespace VectorDrawable
+} // namespace VectorDrawable
typedef VectorDrawable::Path::Data PathData;
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
-#endif // ANDROID_HWUI_VPATH_H
+#endif // ANDROID_HWUI_VPATH_H