DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Text.cpp Source File

Text.cpp

00001 /*******************************************************************************
00002 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all
00030 * ownership rights.
00031 *******************************************************************************/
00032 
00033 #include <algorithm>
00034 #include <functional>
00035 #include <list>
00036 #include "Bitmap.hpp"
00037 #include "Display.hpp"
00038 #include "Text.hpp"
00039 
00040 using std::string;
00041 
00042 static const int invalidWidthHeight = -1;
00043 
00044 static const int characterWidth = 5;
00045 static const int characterHeight = 7;
00046 
00047 static const unsigned char printableCharBegin = 0x20;
00048 static const unsigned char printableCharEnd = 0x7E;
00049 
00050 static const uint8_t characterMap[][characterHeight] = {
00051     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ' '
00052     {0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20}, // '!'
00053     {0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00}, // '"'
00054     {0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50}, // '#'
00055     {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20}, // '$'
00056     {0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18}, // '%'
00057     {0x60, 0x90, 0xA0, 0x40, 0xA8, 0x90, 0x68}, // '&'
00058     {0x60, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00}, // '''
00059     {0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10}, // '('
00060     {0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40}, // ')'
00061     {0x00, 0x20, 0xA8, 0x70, 0xA8, 0x20, 0x00}, // '*'
00062     {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00}, // '+'
00063     {0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x40}, // ','
00064     {0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00}, // '-'
00065     {0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60}, // '.'
00066     {0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, // '/'
00067     {0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70}, // '0'
00068     {0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70}, // '1'
00069     {0x70, 0x88, 0x08, 0x10, 0x20, 0x40, 0xF8}, // '2'
00070     {0xF8, 0x10, 0x20, 0x10, 0x08, 0x88, 0x70}, // '3'
00071     {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10}, // '4'
00072     {0xF8, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70}, // '5'
00073     {0x30, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70}, // '6'
00074     {0xF8, 0x08, 0x10, 0x20, 0x40, 0x40, 0x40}, // '7'
00075     {0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70}, // '8'
00076     {0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0x60}, // '9'
00077     {0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00}, // ':'
00078     {0x00, 0x60, 0x60, 0x00, 0x60, 0x20, 0x40}, // ';'
00079     {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10}, // '<'
00080     {0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00}, // '='
00081     {0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40}, // '>'
00082     {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20}, // '?'
00083     {0x70, 0x88, 0x08, 0x68, 0xA8, 0xA8, 0x70}, // '@'
00084     {0x70, 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88}, // 'A'
00085     {0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0}, // 'B'
00086     {0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70}, // 'C'
00087     {0xE0, 0x90, 0x88, 0x88, 0x88, 0x90, 0xE0}, // 'D'
00088     {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8}, // 'E'
00089     {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80}, // 'F'
00090     {0x70, 0x88, 0x80, 0xB8, 0x88, 0x88, 0x78}, // 'G'
00091     {0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88}, // 'H'
00092     {0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, // 'I'
00093     {0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60}, // 'J'
00094     {0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88}, // 'K'
00095     {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8}, // 'L'
00096     {0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88}, // 'M'
00097     {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88}, // 'N'
00098     {0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, // 'O'
00099     {0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80}, // 'P'
00100     {0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68}, // 'Q'
00101     {0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88}, // 'R'
00102     {0x78, 0x80, 0x80, 0x70, 0x08, 0x08, 0xF0}, // 'S'
00103     {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, // 'T'
00104     {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, // 'U'
00105     {0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20}, // 'V'
00106     {0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50}, // 'W'
00107     {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88}, // 'X'
00108     {0x88, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20}, // 'Y'
00109     {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8}, // 'Z'
00110     {0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70}, // '['
00111     {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00}, // '\'
00112     {0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70}, // ']'
00113     {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00}, // '^'
00114     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8}, // '_'
00115     {0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00}, // '`'
00116     {0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78}, // 'a'
00117     {0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0xF0}, // 'b'
00118     {0x00, 0x00, 0x70, 0x80, 0x80, 0x88, 0x70}, // 'c'
00119     {0x08, 0x08, 0x68, 0x98, 0x88, 0x88, 0x78}, // 'd'
00120     {0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70}, // 'e'
00121     {0x30, 0x48, 0x40, 0xE0, 0x40, 0x40, 0x40}, // 'f'
00122     {0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x70}, // 'g'
00123     {0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88}, // 'h'
00124     {0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70}, // 'i'
00125     {0x10, 0x00, 0x30, 0x10, 0x10, 0x90, 0x60}, // 'j'
00126     {0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90}, // 'k'
00127     {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, // 'l'
00128     {0x00, 0x00, 0xD0, 0xA8, 0xA8, 0x88, 0x88}, // 'm'
00129     {0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88}, // 'n'
00130     {0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70}, // 'o'
00131     {0x00, 0x00, 0xF0, 0x88, 0xF0, 0x80, 0x80}, // 'p'
00132     {0x00, 0x00, 0x68, 0x98, 0x78, 0x08, 0x08}, // 'q'
00133     {0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80}, // 'r'
00134     {0x00, 0x00, 0x70, 0x80, 0x70, 0x08, 0xF0}, // 's'
00135     {0x40, 0x40, 0xE0, 0x40, 0x40, 0x48, 0x30}, // 't'
00136     {0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68}, // 'u'
00137     {0x00, 0x00, 0x88, 0x88, 0x88, 0x41, 0x20}, // 'v'
00138     {0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50}, // 'w'
00139     {0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88}, // 'x'
00140     {0x00, 0x00, 0x88, 0x88, 0x78, 0x08, 0x70}, // 'y'
00141     {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8}, // 'z'
00142     {0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10}, // '{'
00143     {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, // '|'
00144     {0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40}, // '}'
00145     {0x00, 0x00, 0x40, 0xA8, 0x10, 0x00, 0x00}  // '~'
00146 };
00147 
00148 static bool charPrintable(unsigned char c) {
00149   return (c >= printableCharBegin) && (c <= printableCharEnd);
00150 }
00151 
00152 static void removeNonprintableChars(string & s) {
00153   s.erase(std::remove_if(s.begin(), s.end(),
00154                          std::not1(std::ptr_fun(charPrintable))),
00155           s.end());
00156 }
00157 
00158 static bool compareStringLength(const string & a, const string & b) {
00159   return a.length() < b.length();
00160 }
00161 
00162 namespace {
00163 
00164 // Functor trims string if it exceeds a certain length.
00165 class TrimString {
00166 public:
00167   TrimString(string::size_type maxSize) : maxSize(maxSize) {}
00168 
00169   void operator()(string & s) {
00170     if (s.size() > maxSize) {
00171       s.resize(maxSize);
00172     }
00173   }
00174 
00175 private:
00176   string::size_type maxSize;
00177 };
00178 
00179 } // namespace
00180 
00181 // Split a string based on a character token. Token will be removed.
00182 static std::list<string> tokenizeString(const string & toSplit, char token) {
00183   std::list<string> toSplitLines;
00184   string::size_type beginIdx = 0, endIdx;
00185   do {
00186     endIdx = toSplit.find(token, beginIdx);
00187     toSplitLines.push_back(toSplit.substr(
00188         beginIdx, endIdx == string::npos ? string::npos : endIdx - beginIdx));
00189     beginIdx = endIdx + 1;
00190   } while (endIdx != string::npos);
00191   return toSplitLines;
00192 }
00193 
00194 // Word wrap string into lines based on a specified line length.
00195 static std::list<string> wrapLines(const string & toSplit,
00196                                    const string::size_type lineLen) {
00197   std::list<string> toSplitLines;
00198   string::size_type beginIdx = 0;
00199   if (lineLen > 0) {
00200     // Split lines as much as necessary.
00201     string::size_type endIdx = lineLen;
00202     while (((toSplit.length() - beginIdx) > lineLen) &&
00203            (endIdx != string::npos)) {
00204       endIdx = toSplit.rfind(' ', endIdx);
00205       if ((endIdx == string::npos) || (endIdx <= beginIdx)) {
00206         // Current word is too long to split. Find end of current word.
00207         endIdx = toSplit.find(' ', beginIdx);
00208       }
00209       if (endIdx != string::npos) {
00210         toSplitLines.push_back(toSplit.substr(beginIdx, endIdx - beginIdx));
00211         beginIdx = endIdx + 1;
00212         endIdx = beginIdx + lineLen;
00213       }
00214     }
00215   }
00216   // Last line is any remaining characters.
00217   toSplitLines.push_back(toSplit.substr(beginIdx, toSplit.length() - beginIdx));
00218   return toSplitLines;
00219 }
00220 
00221 Text::Text()
00222     : text_(), wordWrap_(false), charSpacing_(1), lineSpacing_(1), textLines_(),
00223       preferredWidth_(invalidWidthHeight),
00224       preferredHeight_(invalidWidthHeight) {}
00225 
00226 void Text::setText(const string & text) {
00227   if (text_ != text) {
00228     text_ = text;
00229     invalidate();
00230     preferredWidth_ = preferredHeight_ = invalidWidthHeight;
00231   }
00232 }
00233 
00234 void Text::setWordWrap(bool wordWrap) {
00235   if (wordWrap_ != wordWrap) {
00236     wordWrap_ = wordWrap;
00237     invalidate();
00238     preferredWidth_ = preferredHeight_ = invalidWidthHeight;
00239   }
00240 }
00241 
00242 void Text::setLineSpacing(int lineSpacing) {
00243   if (lineSpacing > 0 && lineSpacing_ != lineSpacing) {
00244     lineSpacing_ = lineSpacing ;
00245     invalidate();
00246     preferredHeight_ = invalidWidthHeight;
00247   }
00248 }
00249 
00250 void Text::setCharSpacing(int charSpacing) {
00251   if (charSpacing > 0 && charSpacing_ != charSpacing) {
00252     charSpacing_ = charSpacing;
00253     invalidate();
00254     preferredWidth_ = invalidWidthHeight;
00255     if (wordWrap()) {
00256       preferredHeight_ = invalidWidthHeight;
00257     }
00258   }
00259 }
00260 
00261 int Text::preferredWidth() const {
00262   if (preferredWidth_ == invalidWidthHeight) {
00263     calculateLayout();
00264   }
00265   return preferredWidth_;
00266 }
00267 
00268 int Text::preferredHeight() const {
00269   if (preferredHeight_ == invalidWidthHeight) {
00270     calculateLayout();
00271   }
00272   return preferredHeight_;
00273 }
00274 
00275 void Text::resized() {
00276   preferredWidth_ = invalidWidthHeight;
00277   if (wordWrap()) {
00278     preferredHeight_ = invalidWidthHeight;
00279   }
00280 }
00281 
00282 void Text::doRender(Bitmap & bitmap, int xOffset, int yOffset) const {
00283   using std::list;
00284 
00285   // Ensure layout is up to date.
00286   if (preferredWidth_ == invalidWidthHeight ||
00287       preferredHeight_ == invalidWidthHeight) {
00288     calculateLayout();
00289   }
00290 
00291   // Render each line.
00292   int lineNum = 0;
00293   for (list<string>::const_iterator lineIt = textLines_.begin();
00294        lineIt != textLines_.end(); ++lineIt) {
00295     // Render each character.
00296     for (string::size_type charNum = 0; charNum < lineIt->length(); ++charNum) {
00297       bitmap.overlay(xOffset + x() + charNum * (characterWidth + charSpacing_),
00298                      yOffset + y() + lineNum * (characterHeight + lineSpacing_),
00299                      &characterMap[(*lineIt)[charNum] - printableCharBegin][0],
00300                      characterHeight, characterWidth);
00301     }
00302     ++lineNum;
00303   }
00304 }
00305 
00306 void Text::calculateLayout() const {
00307   using std::list;
00308 
00309   // Split string into lines.
00310   textLines_ = tokenizeString(text_, '\n');
00311 
00312   // Remove non-printable characters.
00313   std::for_each(textLines_.begin(), textLines_.end(), removeNonprintableChars);
00314 
00315   const int lineLen =
00316       (width() / (characterWidth + charSpacing_)) +
00317       (((width() % (characterWidth + charSpacing_)) >= characterWidth) ? 1 : 0);
00318   const int numLines =
00319       (height() / (characterHeight + lineSpacing_)) +
00320       (((height() % (characterHeight + lineSpacing_)) >= characterHeight) ? 1
00321                                                                           : 0);
00322 
00323   // Word wrap lines if enabled.
00324   if (wordWrap_) {
00325     list<string>::iterator lineIt = textLines_.begin();
00326     while (lineIt != textLines_.end()) {
00327       list<string>::iterator nextLineIt = lineIt;
00328       ++nextLineIt;
00329 
00330       // Wrap current line.
00331       list<string> wrappedLines = wrapLines(*lineIt, lineLen);
00332       textLines_.splice(lineIt, wrappedLines);
00333       // Remove old line.
00334       textLines_.erase(lineIt);
00335 
00336       lineIt = nextLineIt;
00337     }
00338   }
00339 
00340   // Calculate preferred size.
00341   string::size_type maxLineLength =
00342       std::max_element(textLines_.begin(), textLines_.end(),
00343                        compareStringLength)
00344           ->length();
00345   preferredWidth_ = (maxLineLength > 0)
00346                         ? (maxLineLength * characterWidth) +
00347                               ((maxLineLength - 1) * charSpacing_)
00348                         : 1;
00349   preferredHeight_ = (textLines_.size() * characterHeight) +
00350                      ((textLines_.size() - 1) * lineSpacing_);
00351 
00352   // Remove clipped text.
00353   if (textLines_.size() > static_cast<list<string>::size_type>(numLines)) {
00354     textLines_.resize(numLines);
00355   }
00356   std::for_each(textLines_.begin(), textLines_.end(), TrimString(lineLen));
00357 }