blob: 302d2b1e126058f931f81338c98cf3e094cbc60d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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.
*/
#ifndef MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
#define MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
#include <algorithm>
#include "minikin/LineBreaker.h"
namespace minikin {
namespace android {
class AndroidLineWidth : public LineWidth {
public:
AndroidLineWidth(float firstWidth, int32_t firstLineCount, float restWidth,
const std::vector<float>& indents, int32_t indentsOffset)
: mFirstWidth(firstWidth),
mFirstLineCount(firstLineCount),
mRestWidth(restWidth),
mIndents(indents),
mOffset(indentsOffset) {}
float getAt(size_t lineNo) const override {
const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount) ? mFirstWidth : mRestWidth;
return std::max(0.0f, width - get(mIndents, lineNo));
}
float getMin() const override {
// A simpler algorithm would have been simply looping until the larger of
// mFirstLineCount and mIndents.size()-mOffset, but that does unnecessary calculations
// when mFirstLineCount is large. Instead, we measure the first line, all the lines that
// have an indent, and the first line after firstWidth ends and restWidth starts.
float minWidth = std::min(getAt(0), getAt(mFirstLineCount));
for (size_t lineNo = 1; lineNo + mOffset < mIndents.size(); lineNo++) {
minWidth = std::min(minWidth, getAt(lineNo));
}
return minWidth;
}
private:
float get(const std::vector<float>& vec, size_t lineNo) const {
if (vec.empty()) {
return 0;
}
const size_t index = lineNo + mOffset;
if (index < vec.size()) {
return vec[index];
} else {
return vec.back();
}
}
const float mFirstWidth;
const int32_t mFirstLineCount;
const float mRestWidth;
const std::vector<float>& mIndents;
const int32_t mOffset;
};
class StaticLayoutNative {
public:
StaticLayoutNative(BreakStrategy strategy, HyphenationFrequency frequency, bool isJustified,
std::vector<float>&& indents)
: mStrategy(strategy),
mFrequency(frequency),
mIsJustified(isJustified),
mIndents(std::move(indents)) {}
LineBreakResult computeBreaks(const U16StringPiece& textBuf, const MeasuredText& measuredText,
// Line width arguments
float firstWidth, int32_t firstWidthLineCount, float restWidth,
int32_t indentsOffset,
// Tab stop arguments
const float* tabStops, int32_t tabStopSize,
float defaultTabStopWidth) const {
AndroidLineWidth lineWidth(firstWidth, firstWidthLineCount, restWidth, mIndents,
indentsOffset);
return breakIntoLines(textBuf, mStrategy, mFrequency, mIsJustified, measuredText, lineWidth,
TabStops(tabStops, tabStopSize, defaultTabStopWidth));
}
inline BreakStrategy getStrategy() const { return mStrategy; }
inline HyphenationFrequency getFrequency() const { return mFrequency; }
inline bool isJustified() const { return mIsJustified; }
private:
const BreakStrategy mStrategy;
const HyphenationFrequency mFrequency;
const bool mIsJustified;
const std::vector<float> mIndents;
const std::vector<float> mLeftPaddings;
const std::vector<float> mRightPaddings;
};
} // namespace android
} // namespace minikin
#endif // MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H